【问题标题】:How can I see a Javascript object's prototype chain?如何查看 Javascript 对象的原型链?
【发布时间】:2011-01-15 14:20:50
【问题描述】:

给定以下代码:

function a() {}
function b() {}
b.prototype = new a();
var b1 = new b();

我们可以保留a 已添加到b 的原型链中。伟大的。而且,以下所有内容都是正确的:

b1 instanceof b
b1 instanceof a
b1 instanceof Object

我的问题是,如果我们不提前知道b1 的来源怎么办?我们如何发现其原型链的成员?理想情况下,我想要一个像 [b, a, Object]["b", "a", "Object"] 这样的数组。

这可能吗?我相信我已经在 SO 上的某个地方看到了一个答案,该答案描述了如何找出这个问题,但我终生无法再次找到它。

【问题讨论】:

    标签: javascript prototype prototypal-inheritance


    【解决方案1】:

    这是一个没有递归函数调用的简单方法

    function getProtoChain(o) {
        const ans = []
        let t = o
        while (t) {
            t = t.__proto__
            ans.push(t)
        }
        return ans
    }
    

    这里是一个使用这个函数的例子

    class A {}
    class B extends A {}
    class C extends B {}
    
    console.log(getProtoChain(new C())) // [C: {}, B: {}, A: {}, {}, null]
    

    【讨论】:

      【解决方案2】:

      另一种获取原型链的方法:

      function getPrototypeChain(obj) {
        let prototypeChain = [];
        (function innerRecursiveFunction(obj) {
          let currentPrototype = (obj != null) ? Object.getPrototypeOf(obj) : null;
          prototypeChain.push(currentPrototype);
          if (currentPrototype != null) {
            innerRecursiveFunction(currentPrototype);
          }
        })(obj);
        return prototypeChain;
      }
      

      【讨论】:

        【解决方案3】:

        edit——这个答案来自 2010 年,已经过时了。从那时起,该语言添加了Object.getPrototypeOf() API,大大简化了流程。


        您可以使用对象的“构造函数”属性在那里找到原型,然后沿着它链接直到到达彩虹的尽头。

        function getPrototypes(o) {
          return (function gp(o, protos) {
            var c = o.constructor;
            if (c.prototype) {
              protos.push(c.prototype);
              return gp(c.prototype, protos);
            }
            return protos;
          })(o, []);
        }
        

        (也许)(或者也许不是 :-) 给我一点时间)(废话;我认为这是可能的,但忽略该代码)

        [edit] 哇,这让我大吃一惊——这个功能很接近但不太正确;建立一系列原型很奇怪,我感到害怕和孤独。我建议只关注上面很棒的@CMS。

        【讨论】:

        • constructor 为您提供尚未从另一个构造函数原型继承的最近原型祖先的构造函数。这几乎不是你想要的。例如,在问题的代码中,b1.constructora,而不是 b,如果你从 b 派生了一个对象 cc1.constructor 仍然是 a。一般的经验法则:永远不要使用constructor。 [eta:lol @‘害怕和孤独’...是的,这是 JavaScript 的一部分,旨在通过做一些看起来有用但实际上是陷阱的事情来迷惑你。]
        • 是的,我认为最初的问题是一个有趣的练习,但我从来没有将它放入我期望实际工作的代码中。这里有一个很好的解释:mckoss.com/jscript/object.htm
        【解决方案4】:

        好吧,对象之间的原型链接 ([[Prototype]]) 是内部的,一些实现,例如 Mozilla,将其公开为 obj.__proto__

        ECMAScript 第 5 版的 Object.getPrototypeOf 方法正是您所需要的,但目前大多数 JavaScript 引擎都没有实现它。

        看看 John Resig 的 implementation,它有一个陷阱,它依赖于不支持 __proto__ 的引擎的 constructor 属性:

        if ( typeof Object.getPrototypeOf !== "function" ) {
          if ( typeof "test".__proto__ === "object" ) {
            Object.getPrototypeOf = function(object){
              return object.__proto__;
            };
          } else {
            Object.getPrototypeOf = function(object){
              // May break if the constructor has been tampered with
              return object.constructor.prototype;
            };
          }
        }
        

        请记住,这不是 100% 可靠的,因为 constructor 属性在任何对象上都是可变的。

        【讨论】:

        • 就像 Javascript 中的任何东西一样,查看对象属性并相信你得到的东西是有风险的 :-)
        • 谢谢,但这告诉我ab1 的原型,但与b 无关。我怎样才能发现b1b 的一个实例?
        • 回退到constructor 不仅是因为潜在的原型篡改而导致的错误,而且一开始是完全错误的,因为constructor 并没有按照您的预期行事(请参阅下面的评论) .这表明 Resig 对基本 JavaScript 功能的无知令人惊讶; 不要使用这个脚本。不过,关于__proto__getPrototypeOf 的信息很好。
        • 那么,bobince,有解决办法吗?这是什么?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-09-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多