Как определить, является ли объект литералом объекта в Javascript?
есть ли способ определить в Javascript, был ли объект создан с помощью
7 ответов
Я только что наткнулся на этот вопрос и поток во время сладкого хакфеста, который включал в себя поиск Грааля для оценки того, был ли объект создан с {} или новым объектом() (я все еще не понял этого.)
во всяком случае, я был удивлен, обнаружив сходство между функцией isObjectLiteral (), размещенной здесь, и моей собственной функцией isObjLiteral (), которую я написал для пыльцы.Проект на JS. Я считаю, что это решение было опубликовано до моей пыльцы.JS commit, so-hats off to you! Потенциал для меня это длина... меньше половины (если включить вашу процедуру настройки), но оба дают одинаковые результаты.
смотрим:
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...
обязательно откройте firebug, когда вы туда попадете-отладка в документ для любителей IE.
Edit: я интерпретирую "объектный литерал" как все, что создано с помощью объектного литерала или на 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 для testcase:
<!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>
литерал объекта-это нотация, используемая для определения объекта, который в javascript всегда находится в виде пары имя-значение, окруженной фигурными скобками. Как только это будет выполнено, невозможно сказать, был ли объект создан этой нотацией или нет (на самом деле, я думаю, что это может быть чрезмерным упрощением, но в основном правильным). У вас просто есть объект. Это одна из замечательных вещей о js в том, что есть много коротких путей, чтобы делать вещи, которые могут быть намного длиннее писать. Короче говоря, буквальная нотация заменяет необходимость писать:
var myobject = new Object();
похоже, вы ищете это:
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
есть очень хорошее объяснение этому в другом ответе здесь и объяснения здесь.
Я думаю, что другие ответы верны, и на самом деле нет способа обнаружить это.
ты хочешь:
Object.getPrototypeOf(obj) === Object.prototype
это проверяет, что объект является простым объектом, созданным с помощьюnew Object()
или {...}
и не какой-то подкласс Object
.
невозможно определить разницу между объектом, построенным из объектного литерала, и объектом, построенным из других средств.
Это немного похоже на вопрос, Можете ли вы определить, была ли создана числовая переменная, присвоив значение " 2 " или "3-1";
Если вам нужно это сделать, вам нужно будет поместить определенную подпись в литерал объекта, чтобы обнаружить позже.
У меня была такая же проблема, поэтому я решил пойти таким путем:
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...