【问题标题】:__proto__ and prototype difference [duplicate]__proto__ 和原型的区别[重复]
【发布时间】:2015-09-29 04:38:29
【问题描述】:

据我所知,函数应该从其prototype 对象继承属性,可以使用.prototype__proto__ 属性访问。

//my prototype Object
var myObj = {
    a: 1,
    b: 2
};

var myFunc = function () {};

// setting function's `prototype` property
myFunc.prototype = myObj;
alert(myFunc.a);
//returns undefined (Why???) I was expecting 1

但是当我尝试以下方法时,

//setting function __proto__ property
myFunc.__proto__ = myObj;
//returns 1
alert(myFunc.a);

那么为什么当我设置myFunc.__proto__ 时它会起作用,而当我设置myFunc.prototype 时它不起作用?

我确实参考了__proto__ VS. prototype in JavaScript,但无法弄清楚。

【问题讨论】:

  • es5.github.io__proto__ 一无所知。这意味着它不是标准的一部分,你不应该使用它。
  • 不,对象的原型(继承它的对象)不是.prototype。您是否阅读了stackoverflow.com/questions/9959727/… 的所有答案?您有什么不明白的地方(我们很乐意对其进行改进)?
  • 那么 .prototype 是干什么用的??
  • 所以这意味着'.prototype'被用作该函数构造的对象的原型,但它与该函数自己的原型无关

标签: javascript function inheritance prototype


【解决方案1】:

__proto__

您实际上可以使用__proto__ 访问对象的内部[[Prototype]] 属性。您可以将[[Prototype]] 视为继承层次结构中当前对象的实际父对象。

prototype

这是一个特殊属性,当设置在(构造函数)函数对象上时,用于为从构造函数创建的实例建立继承链。例如,

function Foo() {}
Foo.prototype = {a: 1};

现在,当您创建Foo 类型的新对象时,新创建对象的内部[[Prototype]] 属性将引用Foo.prototype 对象。你可以这样确认

console.assert((new Foo()).__proto__ === Foo.prototype);

在你的情况下,

myFunc.prototype = myObj;

您正在函数对象上创建prototype 属性,并且仅当您使用此函数(构造函数)创建新对象时才会使用该属性。您可能想将其视为新对象的模板。因此,当您执行myFunc.a 时,JS 引擎会尝试在原型链中的myFunc 及其父级中找到a,但它没有找到它,这就是它返回undefined 的原因。

但是,当你这样做时

myFunc.__proto__ = myObj;

您正在将原型链中myFunc 的父级设置为myObj。因此,当您执行myFunc.a 时,JS 引擎首先会尝试在myFunc 对象本身中找到a,但它并不存在。因此,它试图在其直接父级中找到它,即myObj。这就是在这种情况下它返回 1 的原因。


注意:您可以使用以下函数更好地理解原型链

function printPrototypeChain(object) {
    while (object !== null) {
        console.log(object);
        object = Object.getPrototypeOf(object);
    }
}

现在,当对象被设置为函数对象的prototype 属性时,让我们打印原型链。

function myFunc() {}
myFunc.prototype = {
    a: 1,
    b: 2
};
printPrototypeChain(myFunc);

输出将是

[Function: myFunc]
[Function: Empty]
{}

这些对象都没有定义a,因此返回undefined。但是,在这种情况下,

function myFunc() {}
myFunc.__proto__ = {
    a: 1,
    b: 2
};
printPrototypeChain(myFunc);

原型链变成这样

[Function: myFunc]
{ a: 1, b: 2 }
{}

并且a 位于myFunc 的直接父级中。所以,返回对应的值1

注意:不要在您的实际代码中使用__proto__,因为它保留在最新版本的 JavaScript 规范中只是为了向后兼容。阅读更多关于它的信息here。请改用Object.getPrototypeOfObject.setPrototypeOf

【讨论】:

  • 一个函数的两个原型......令人困惑!!!
  • 当你做 myFunc.prototype = myObj; myObj 可用于 myFunc 实例,而不适用于 myFunc 它本身。 var x = new myFunc();控制台.log(x.a); //返回1
【解决方案2】:

您混淆了myFunc,它是一个构造函数,instancemyFunc

如果你这样做:

var o = new myFunc();
alert(o.a);

它会提醒 1 因为omyFunc 的一个实例,所以它的a 属性来自myFunc 原型。

如果你设置了__proto__,你实际上是在换掉myFunc从之前继承的函数原型,并用你的原型对象替换它。事实上,在你这样做之后,任何你可以在函数上正常使用的方法,比如call,都不会再在myFunc上找到了。

myFunc.__proto__ = myObj;
myFunc.call(null); // Will throw an error

【讨论】:

    【解决方案3】:

    所有 JS 对象都有__proto__ 系统属性。如果您尝试获取对象a 的属性x 值,首先在对象a 属性中搜索此属性。如果没有找到该属性,则将在a.__proto__ peroperties 中搜索该属性。等等。 这就是为什么 myFunc.a ruturns 1 在你的例子中。 当您设置myFunc.prototype=myObj 时,这意味着将来您创建myFunc 的实例时将使用myObj

    var mf = new myFunc();
    

    这并不意味着myFunc 本身必须有a 属性,正如我上面提到的那样。

    【讨论】:

      猜你喜欢
      • 2021-01-26
      • 2016-10-29
      • 1970-01-01
      • 2021-11-29
      • 1970-01-01
      • 1970-01-01
      • 2012-03-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多