__proto__和原型差异

时间:2015-07-10 12:19:20

标签: javascript function inheritance prototype

据我所知,函数应该从其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,但无法弄清楚。

3 个答案:

答案 0 :(得分:15)

<强> __proto__

您实际上可以使用[[Prototype]]访问对象的内部__proto__属性。您可以将[[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引擎会尝试在a中找到myFunc及其原型链中的父项,但它找不到它,这就是它返回的原因{ {1}}。

但是,当你这样做时

undefined

您要将原型链中的myFunc.__proto__ = myObj; 的父级设置为myFunc。因此,当你执行myObj时,JS引擎首先尝试在myFunc.a对象本身中找到a,但它不在那里。因此,它试图在其直接父代中找到它,即myFunc。这就是为什么在这种情况下它会返回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,因为它是为了向后兼容而保留在最新版本的JavaScript规范中。阅读更多相关信息here。请改用Object.getPrototypeOfObject.setPrototypeOf

答案 1 :(得分:1)

您将myFunc(一个构造函数)与myFunc实例混淆。

如果您这样做:

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

答案 2 :(得分:0)

所有JS对象都具有rst.MoveNext系统属性。如果您尝试获取对象Do while not rst.EOF CountCheck = CountCheck + 1 response.write("Count is: " & CountCheck & "<br>") rst.MoveNext Loop 的有效__proto__值,则首先在对象x属性中搜索此属性。如果找不到任何内容,将在a个性能中搜索该属性。等等。 这就是您的示例中a ruturns a.__proto__的原因。 当您设置myFunc.a时,这意味着在您创建1的实例时将来会使用myFunc.prototype=myObj

myObj

这并不意味着myFunc必须有var mf = new myFunc(); 本身,正如我上面提到的那样。