【问题标题】:How to determine if an object is an object literal in Javascript?如何确定对象是否是Javascript中的对象文字?
【发布时间】:2010-11-13 11:58:28
【问题描述】:

有没有办法在 Javascript 中确定对象是使用object-literal 表示法还是使用构造方法创建的?

在我看来,您只是访问它的父对象,但如果您传入的对象没有对其父对象的引用,我认为您无法说出这一点,对吗?

【问题讨论】:

  • jeresig 让我实现一个功能,为他做这件事。
  • 一个对象永远不是一个对象字面量,所以你能改写一下这个问题吗?
  • 顺便问一下,你最喜欢的 Commodore 64 杂志是什么?
  • @Nosredna 我觉得我当时还太年轻,我在 3 岁时得到了我的第一个 C64。我只知道整体:加载 "*", 8, 1 东西,这样我就可以加载我的游戏了。

标签: javascript oop object-literal


【解决方案1】:

你想要的是:

Object.getPrototypeOf(obj) === Object.prototype

这会检查该对象是使用new Object(){...} 创建的普通对象,而不是Object 的某个子类。

【讨论】:

    【解决方案2】:

    我刚刚在一个甜蜜的 hackfest 中遇到了这个问题和线程,其中涉及评估一个对象是使用 {} 还是 new Object() 创建的圣杯任务(我还没有弄清楚。)

    无论如何,我很惊讶地发现这里发布的 isObjectLiteral() 函数与我自己为 Pollen.JS 项目编写的 isObjLiteral() 函数之间的相似之处。我相信这个解决方案是在我提交 Pollen.JS 之前发布的,所以 - 向你致敬!我的好处是长度......不到一半(包括您的设置例程),但两者产生相同的结果。

    看看:

    函数 isObjLiteral(_obj) { 变量 _test = _obj; return ( typeof _obj !== 'object' || _obj === null ? 错误的 : ( (功能 () { 而(!假){ if ( Object.getPrototypeOf( _test = Object.getPrototypeOf(_test) ) === null) { 休息; } } 返回 Object.getPrototypeOf(_obj) === _test; })() ) ); }

    另外,一些测试的东西:

    var _cases= { _objLit:{}, _objNew:新对象(), _function:新函数(), _array:新数组(), _string:新字符串(), _image:新图像(), _bool: 真 }; 控制台.dir(_cases); for ( _cases 中的 var _test ) { 控制台.组(_test); 控制台.dir({ 类型:typeof _cases[_test], 字符串:_cases[_test].toString(), 结果:isObjLiteral(_cases[_test]) }); 控制台.groupEnd(); }

    或者在 jsbin.com 上...

    http://jsbin.com/iwuwa

    到达那里时一定要打开 firebug - 调试文档是为 IE 爱好者准备的。

    【讨论】:

    • @Rick,这个解决方案似乎更优雅。
    • @leeand00:它的长度和我的差不多。我也刚刚在我的中包含了 Object.getPrototypeOf 的一个实现,这个 不包含
    • 另外,如果你去掉 Object.getPrototypeOf.isNative 部分,我的只有 6 个 SLOC。
    • mhm...你能解释一下为什么你在 while 循环条件中写的是 !false 而不是 true 吗?
    • 为什么不只是Object.getPrototypeOf(Object.getPrototypeOf(_obj))===null
    【解决方案3】:

    编辑:我将“对象文字”解释为使用对象文字 Object 构造函数创建的任何内容。这就是 John Resig 最有可能的意思。

    即使.constructor 已被污染或对象是在另一个框架中创建的,我也有一个可以工作的函数。请注意,Object.prototype.toString.call(obj) === "[object Object]"(有些人可能认为)不会解决这个问题。

    function isObjectLiteral(obj) {
        if (typeof obj !== "object" || obj === null)
            return false;
    
        var hasOwnProp = Object.prototype.hasOwnProperty,
        ObjProto = obj;
    
        // get obj's Object constructor's prototype
        while (Object.getPrototypeOf(ObjProto = Object.getPrototypeOf(ObjProto)) !== null);
    
        if (!Object.getPrototypeOf.isNative) // workaround if non-native Object.getPrototypeOf
            for (var prop in obj)
                if (!hasOwnProp.call(obj, prop) && !hasOwnProp.call(ObjProto, prop)) // inherited elsewhere
                    return false;
    
        return Object.getPrototypeOf(obj) === ObjProto;
    };
    
    
    if (!Object.getPrototypeOf) {
        if (typeof ({}).__proto__ === "object") {
            Object.getPrototypeOf = function (obj) {
                return obj.__proto__;
            };
            Object.getPrototypeOf.isNative = true;
        } else {
            Object.getPrototypeOf = function (obj) {
                var constructor = obj.constructor,
                oldConstructor;
                if (Object.prototype.hasOwnProperty.call(obj, "constructor")) {
                    oldConstructor = constructor;
                    if (!(delete obj.constructor)) // reset constructor
                        return null; // can't delete obj.constructor, return null
                    constructor = obj.constructor; // get real constructor
                    obj.constructor = oldConstructor; // restore constructor
                }
                return constructor ? constructor.prototype : null; // needed for IE
            };
            Object.getPrototypeOf.isNative = false;
        }
    } else Object.getPrototypeOf.isNative = true;
    

    这是测试用例的 HTML:

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8"/>
        <!-- Online here: http://code.eligrey.com/testcases/all/isObjectLiteral.html -->
        <title>isObjectLiteral</title>
        <style type="text/css">
        li { background: green; } li.FAIL { background: red; }
        iframe { display: none; }
        </style>
    </head>
    <body>
    <ul id="results"></ul>
    <script type="text/javascript">
    function isObjectLiteral(obj) {
        if (typeof obj !== "object" || obj === null)
            return false;
    
        var hasOwnProp = Object.prototype.hasOwnProperty,
        ObjProto = obj;
    
        // get obj's Object constructor's prototype
        while (Object.getPrototypeOf(ObjProto = Object.getPrototypeOf(ObjProto)) !== null);
    
        if (!Object.getPrototypeOf.isNative) // workaround if non-native Object.getPrototypeOf
            for (var prop in obj)
                if (!hasOwnProp.call(obj, prop) && !hasOwnProp.call(ObjProto, prop)) // inherited elsewhere
                    return false;
    
        return Object.getPrototypeOf(obj) === ObjProto;
    };
    
    
    if (!Object.getPrototypeOf) {
        if (typeof ({}).__proto__ === "object") {
            Object.getPrototypeOf = function (obj) {
                return obj.__proto__;
            };
            Object.getPrototypeOf.isNative = true;
        } else {
            Object.getPrototypeOf = function (obj) {
                var constructor = obj.constructor,
                oldConstructor;
                if (Object.prototype.hasOwnProperty.call(obj, "constructor")) {
                    oldConstructor = constructor;
                    if (!(delete obj.constructor)) // reset constructor
                        return null; // can't delete obj.constructor, return null
                    constructor = obj.constructor; // get real constructor
                    obj.constructor = oldConstructor; // restore constructor
                }
                return constructor ? constructor.prototype : null; // needed for IE
            };
            Object.getPrototypeOf.isNative = false;
        }
    } else Object.getPrototypeOf.isNative = true;
    
    // Function serialization is not permitted
    // Does not work across all browsers
    Function.prototype.toString = function(){};
    
    // The use case that we want to match
    log("{}", {}, true);
    
    // Instantiated objects shouldn't be matched
    log("new Date", new Date, false);
    
    var fn = function(){};
    
    // Makes the function a little more realistic
    // (and harder to detect, incidentally)
    fn.prototype = {someMethod: function(){}};
    
    // Functions shouldn't be matched
    log("fn", fn, false);
    
    // Again, instantiated objects shouldn't be matched
    log("new fn", new fn, false);
    
    var fn2 = function(){};
    
    log("new fn2", new fn2, false);
    
    var fn3 = function(){};
    
    fn3.prototype = {}; // impossible to detect (?) without native Object.getPrototypeOf
    
    log("new fn3 (only passes with native Object.getPrototypeOf)", new fn3, false);
    
    log("null", null, false);
    
    log("undefined", undefined, false);
    
    
    /* Note:
     * The restriction against instantiated functions is
     * due to the fact that this method will be used for
     * deep-cloning an object. Instantiated objects will
     * just have their reference copied over, whereas
     * plain objects will need to be completely cloned.
     */
    
    var iframe = document.createElement("iframe");
    document.body.appendChild(iframe);
    
    var doc = iframe.contentDocument || iframe.contentWindow.document;
    doc.open();
    doc.write("<body onload='window.top.iframeDone(Object);'>");
    doc.close();
    
    function iframeDone(otherObject){
        // Objects from other windows should be matched
        log("new otherObject", new otherObject, true);
    }
    
    function log(msg, a, b) {
      var pass = isObjectLiteral(a) === b ? "PASS" : "FAIL";
    
      document.getElementById("results").innerHTML +=
        "<li class='" + pass + "'>" + msg + "</li>";
    }
    
    
    </script>
    </body>
    </html>
    

    【讨论】:

    • 很好的答案,很高兴你在 stackoverflow 上。离题,但也感谢 e4x 数组方法。
    • 现在我已经阅读了您的回答,我认为我理解了这个问题。
    • 哇! (===) 的 3x 等号是什么?
    • @leeand00 表示“完全等于”。例如: var x = {valueOf:function(){return 1}}; (x == 1) === 真; (x === 1) === 真;
    • 第二个例子应该以 === false 我的意思结束。
    【解决方案4】:

    听起来你正在寻找这个:

    function Foo() {}
    
    var a = {};
    var b = new Foo();
    
    console.log(a.constructor == Object); // true
    console.log(b.constructor == Object); // false
    

    对象的构造函数属性是指向用于构造它的函数的指针。在上面的例子中b.constructor == Foo。如果对象是使用大括号(数组文字符号)或使用new Object() 创建的,则其构造函数属性将为== Object

    更新: crescentfresh 指出$(document).constructor == Object 不等于 jQuery 构造函数,所以我做了一点挖掘。似乎通过使用对象字面量作为对象的原型,您的构造函数属性几乎一文不值:

    function Foo() {}
    var obj = new Foo();
    obj.constructor == Object; // false
    

    但是:

    function Foo() {}
    Foo.prototype = { objectLiteral: true };
    var obj = new Foo();
    obj.constructor == Object; // true
    

    另一个答案here对此有很好的解释,还有一个更复杂的解释here

    我认为其他答案是正确的,没有办法检测到这一点。

    【讨论】:

    • constructor === Object 适用于很多对象。例如在此页面上尝试javascript:alert($(document).constructor === Object),即使jQuery !== Object
    • 如果测试“对象”是null,这个方法会抛出错误
    【解决方案5】:

    对象字面量是您用来定义对象的符号 - 在 javascript 中,它始终采用由大括号括起来的名称-值对的形式。一旦执行此操作,就无法判断对象是否是通过此表示法创建的(实际上,我认为这可能过于简单,但基本上是正确的)。你只有一个对象。这是 js 的一大优点,因为有很多捷径可以做一些可能需要更长的时间来编写的事情。简而言之,文字符号代替了必须写:

    var myobject = new Object();
    

    【讨论】:

      【解决方案6】:

      我有同样的问题,所以我决定走这条路:

      function isPlainObject(val) {
        return val ? val.constructor === {}.constructor : false;
      }
      // Examples:
      isPlainObject({}); // true
      isPlainObject([]); // false
      isPlainObject(new Human("Erik", 25)); // false
      isPlainObject(new Date); // false
      isPlainObject(new RegExp); // false
      //and so on...
      

      【讨论】:

      • @Quentin Engles,为什么不呢?我已经在不同的浏览器中测试过了,你自己试试吧。
      • 就像在具有构造函数的对象上将构造函数属性设置为 Object 一样。再说一次,如果一个人想要的只是判断某物是否是文字,而不是如果不是,那么我不知道。
      • isPlainObject( JSON ) 失败(返回真)
      【解决方案7】:

      没有办法区分从对象字面量构建的对象与从其他方式构建的对象之间的区别。

      这有点像问你是否可以通过赋值'2'或'3-1'来确定是否构造了一个数字变量;

      如果你需要这样做,你必须在你的对象文字中加入一些特定的签名以便以后检测。

      【讨论】:

        【解决方案8】:

        现在有一个更优雅的解决方案可以准确地回答您的问题:

        function isObject(value) {
          return value !== null && value !== undefined && Object.is(value.constructor, Object)
        }
        
        // Test stuff below //
        
        class MyClass extends Object {
          constructor(args) {
            super(args)
          }
          say() {
            console.log('hello')
          }
        }
        
        function MyProto() {
          Object.call(this)
        }
        MyProto.prototype = Object.assign(Object.create(Object.prototype), {
        
          constructor: MyProto,
        
          say: function() {
            console.log('hello')
          }
        
        });
        
        const testsCases = {
          objectLiteral: {},
          objectFromNew: new Object(),
          null: null,
          undefined: undefined,
          number: 123,
          function: new Function(),
          array: new Array([1, 2, 3]),
          string: new String('foobar'),
          image: new Image(),
          bool: true,
          error: new Error('oups'),
          myClass: new MyClass(),
          myProto: new MyProto()
        }
        
        for (const [key, value] of Object.entries(testsCases)) {
          console.log(`${key.padEnd(15)} => ${isObject(value)}`)
        }

        最好的问候

        【讨论】:

          【解决方案9】:

          11 岁的问题是我的整洁解决方案,对边缘案例建议持开放态度; 步骤 -> 仅查找对象然后比较以检查属性 -> 对象文字没有长度、原型和边缘情况 stringyfy 属性。

          在测试 JSON 和 Object.create(Object.create({cool: "joes"})).

           "use strict"
          let isObjectL = a => { 
                  if (typeof a !=='object' || ['Number','String','Boolean', 'Symbol'].includes(a.constructor.name)) return false;
                 let props = Object.getOwnPropertyNames(a);
                  if ( !props.includes('length') && !props.includes('prototype') || !props.includes('stringify')) return true;
                   };
          
          
          let A={type:"Fiat", model:"500", color:"white"};
          let B= new Object();
          let C = { "name":"John", "age":30, "city":"New York"};
          let D= '{ "name":"John", "age":30, "city":"New York"}';
          let E = JSON.parse(D);
          let F = new Boolean();
          let G = new Number();
              
              console.log(isObjectL(A));
              
              console.log(isObjectL(B));
              
              console.log(isObjectL(C));
              
              console.log(isObjectL(D));
              
              console.log(isObjectL(E));
              
              console.log(isObjectL(JSON));
              
              console.log(isObjectL(F));
              
              console.log(isObjectL(G));
              
              console.log(isObjectL(
          Object.create(Object.create({cool: "joes"}))));
          
              
              console.log(isObjectL());

          另一个显示内部工作的变体

          isObject=function(a) { 
              let exclude = ['Number','String','Boolean', 'Symbol'];
              let types = typeof a;
              let props = Object.getOwnPropertyNames(a);
              console.log((types ==='object' && !exclude.includes(a.constructor.name) &&
              ( !props.includes('length') && !props.includes('prototype') && !props.includes('stringify'))));
              return `type: ${types} props: ${props}
              ----------------`}
              
              A={type:"Fiat", model:"500", color:"white"};
          B= new Object();
          C = { "name":"John", "age":30, "city":"New York"};
          D= '{ "name":"John", "age":30, "city":"New York"}';
          E = JSON.parse(D);
          F = new Boolean();
          G = new Number();
              
              console.log(isObject(A));
              
              console.log(isObject(B));
              
              console.log(isObject(C));
              
              console.log(isObject(D));
              
              console.log(isObject(E));
              
              console.log(isObject(JSON));
              
              console.log(isObject(F));
              
              console.log(isObject(G));
              
              console.log(isObject(
          Object.create(Object.create({cool: "joes"}))));

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2010-11-30
            • 2011-03-19
            • 2022-12-04
            • 2011-12-12
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多