代码之家  ›  专栏  ›  技术社区  ›  leeand00

如何确定一个对象是否是javascript中的对象文本?

  •  17
  • leeand00  · 技术社区  · 15 年前

    在javascript中,是否有任何方法可以确定是否使用 object-literal 表示法还是使用构造函数方法?

    在我看来,你只是访问它的父对象,但是如果你传入的对象没有对它的父对象的引用,我认为你不能告诉我,是吗?

    7 回复  |  直到 8 年前
        1
  •  11
  •   Rick    15 年前

    我刚刚在一次甜蜜的黑客大会上遇到了这个问题和线索,这涉及到一个评估对象是用还是new object()创建的Grail任务(我还没有弄清楚)。

    不管怎样,我很惊讶地发现这里发布的isObjectLiteral()函数和我为palment.js项目编写的isObjectLiteral()函数之间的相似性。我相信这个解决方案是在我提交palment.js之前发布的,所以-向你致敬!我的优势是长度…少于一半(包括设置程序),但两者产生的结果相同。

    看一看:

    function isObjLiteral(_obj) {
      var _test  = _obj;
      return (  typeof _obj !== 'object' || _obj === null ?
                  false :  
                  (
                    (function () {
                      while (!false) {
                        if (  Object.getPrototypeOf( _test = Object.getPrototypeOf(_test)  ) === null) {
                          break;
                        }      
                      }
                      return Object.getPrototypeOf(_obj) === _test;
                    })()
                  )
              );
    }
    

    此外,一些测试材料:

    var _cases= {
        _objLit : {}, 
        _objNew : new Object(),
        _function : new Function(),
        _array : new Array(), 
        _string : new String(),
        _image : new Image(),
        _bool: true
    };
    
    console.dir(_cases);
    
    for ( var _test in _cases ) {
      console.group(_test);
      console.dir( {
        type:    typeof _cases[_test], 
        string:  _cases[_test].toString(), 
        result:  isObjLiteral(_cases[_test])  
      });    
      console.groupEnd();
    }
    

    或者在jsbin.com上…

    http://jsbin.com/iwuwa

    一定要打开Firebug当你到达那里-调试文件是为IE爱好者。

        2
  •  11
  •   Eli Grey    15 年前

    编辑: 我将“对象文字”解释为使用对象文字创建的任何内容 这个 Object 构造函数。这就是约翰·雷西格最可能的意思。

    我有一个即使在 .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>
    
        3
  •  5
  •   Community CDub    8 年前

    听起来你在找这个:

    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 .

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

        4
  •  4
  •   Steve Mc    15 年前

    对象文本是用于定义对象的符号,在javascript中,它总是以名称-值对的形式由大括号包围。一旦执行了这个操作,就无法判断对象是否是用这个符号创建的(实际上,我认为这可能是一个过度简化,但基本上是正确的)。你只有一个物体。这是关于JS的一个很好的地方,因为有很多短文要做的事情可能需要更长的时间来编写。简而言之,文字符号取代了必须写:

    var myobject = new Object();
    
        5
  •  3
  •   Jesse timdev    8 年前

    你想要的是:

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

    这将检查对象是否是使用 new Object() {...} 而不是 Object .

        6
  •  2
  •   Paul Dixon    15 年前

    无法区分从对象文字构建的对象与从其他方式构建的对象之间的区别。

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

    如果需要这样做,您必须在对象文本中放置一些特定的签名,以便稍后检测。

        7
  •  1
  •   a8m    10 年前

    我也有同样的问题,所以我决定这样做:

    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...