Как определить, является ли объект литералом объектов в JavaScript?

Дилберт http://www.laputan.org/images/pictures/elbonia-900406.gif

Это - что-то, что я нашел чтением об антишаблонах.

17
задан tvanfosson 24 July 2009 в 10:56
поделиться

5 ответов

Я только что натолкнулся на этот вопрос и тред во время сладкого хакфеста, который включал поиск Грааля для оценки того, был ли объект создан с помощью {} или new Object () (я до сих пор не понял этого. )

В любом случае, я был удивлен, обнаружив сходство между опубликованной здесь функцией isObjectLiteral () и моей собственной функцией isObjLiteral (), которую я написал для проекта Pollen.JS. Я считаю, что это решение было опубликовано до моего коммита Pollen.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.

12
ответ дан 30 November 2019 в 11:22
поделиться

Изменить: Я интерпретирую «литерал объекта» как что-либо, созданное с использованием литерала объекта или конструктора объекта . Скорее всего, именно это имел в виду Джон Ресиг.

У меня есть функция, которая будет работать, даже если .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>
11
ответ дан 30 November 2019 в 11:22
поделиться

Похоже, вы ищете это:

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

Это очень хорошее объяснение в другом ответе здесь , и более сложное объяснение здесь .

Я думаю, что другие ответы верны, и на самом деле нет способа обнаружить это.

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

Это очень хорошее объяснение в другом ответе здесь , и более сложное объяснение здесь .

Я думаю, что другие ответы верны, и на самом деле нет способа обнаружить это.

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

Это очень хорошее объяснение в другом ответе здесь , и более сложное объяснение здесь .

Я думаю, что другие ответы верны, и на самом деле нет способа обнаружить это.

6
ответ дан 30 November 2019 в 11:22
поделиться

Невозможно определить разницу между объектом, созданным из литерала объекта, и объектом, построенным с помощью других средств.

Это немного похоже на вопрос, можете ли вы определить, является ли числовая переменная был создан путем присвоения значения «2» или «3-1»;

Если вам нужно это сделать, вам нужно будет добавить некоторую конкретную сигнатуру в литерал вашего объекта для последующего обнаружения.

2
ответ дан 30 November 2019 в 11:22
поделиться

Литерал объекта - это обозначение, которое вы используете для определения объекта, который в javascript всегда имеет форму имени. пара -значение в фигурных скобках. После того, как это было выполнено, невозможно определить, был ли объект создан с помощью этой нотации (на самом деле, я думаю, что это может быть чрезмерным упрощением, но в основном правильно). У вас просто есть объект. Это одна из замечательных особенностей js в том, что есть множество сокращений, позволяющих делать вещи, на написание которых может потребоваться гораздо больше времени. Короче говоря, буквальные обозначения заменяют необходимость писать:

var myobject = new Object();
4
ответ дан 30 November 2019 в 11:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: