23

オブジェクトがオブジェクトリテラル表記を使用して作成されたか、コンストラクターメソッドを使用して作成されたかをJavascriptで判断する方法はありますか?

親オブジェクトにアクセスするだけのように見えますが、渡したオブジェクトにその親への参照がない場合、これはわかりませんね。

4

10 に答える 10

13

オブジェクトが{}または新しいObject()で作成されたかどうかを評価するための大胆な探求を含む甘いハックフェスト中にこの質問とスレッドに出くわしました(私はまだそれを理解していません)。

とにかく、ここに投稿されたisObjectLiteral()関数と、Pollen.JSプロジェクト用に作成した自分のisObjLiteral()関数との類似性を見つけて驚いた。このソリューションは、Pollen.JSがコミットする前に投稿されたと思います。私の利点は長さです...半分未満(セットアップルーチンを含めると)ですが、どちらも同じ結果になります。

見てください:

関数isObjLiteral(_obj){
  var _test = _obj;
  return(typeof _obj!=='object' || _obj === null?
              false:  
              ((
                (働き () {
                  while(!false){
                    if(Object.getPrototypeOf(_test = Object.getPrototypeOf(_test))=== null){
                      壊す;
                    }      
                  }
                  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({
    タイプ:typeof _cases [_test]、
    文字列:_cases [_test] .toString()、
    結果:isObjLiteral(_cases [_test])  
  });    
  console.groupEnd();
}

またはjsbin.comで...

http://jsbin.com/iwuwa

そこに着いたら、必ずfirebugを開いてください。ドキュメントのデバッグはIE愛好家向けです。

于 2009-09-26T21:22:23.873 に答える
11

編集:私は「オブジェクトリテラル」を、オブジェクトリテラルまたは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>
于 2009-07-24T02:18:12.277 に答える
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()そのコンストラクタ プロパティ willを使用して作成された場合== Object

更新:$(document).constructor == Object crescentfreshは、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に非常に良い説明があります。

他の答えは正しいと思いますが、これを検出する方法は実際にはありません。

于 2009-07-23T22:10:49.563 に答える
4

オブジェクト リテラルは、オブジェクトを定義するために使用する表記法です。これは、javascript では常に中括弧で囲まれた名前と値のペアの形式です。これが実行されると、オブジェクトがこの表記法によって作成されたかどうかを判断する方法はありません (実際には、単純化しすぎている可能性がありますが、基本的には正しいと思います)。あなたはちょうどオブジェクトを持っています。これは js の優れた点の 1 つであり、記述するのに時間がかかる可能性があることを実行するためのショートカットが多数あるという点です。要するに、リテラル表記は、次のように書く必要を置き換えます。

var myobject = new Object();
于 2009-07-23T18:37:04.767 に答える
4

私は同じ問題を抱えていたので、この方法で行くことにしました:

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...
于 2014-10-12T11:26:02.843 に答える
2

オブジェクトリテラルから構築されたオブジェクトと、他の手段から構築されたオブジェクトとの違いを見分ける方法はありません。

これは、値 '2' または '3-1' を割り当てることによって数値変数が構築されたかどうかを判断できるかどうかを尋ねるのと少し似ています。

これを行う必要がある場合は、オブジェクト リテラルに特定の署名を入れて、後で検出する必要があります。

于 2009-07-23T18:28:35.080 に答える