在这段代码中:
html {overflow-y: scroll;}
当var Fruit = function() {}
Fruit.prototype = {
color: function () {
console.log('Fruit color...')
}
}
var Apple = function () {}
Apple.prototype = new Fruit()
Apple.prototype.constructor = Apple
var a = new Apple()
Apple.prototype = null // the question!!!
a.color()
设置为Apple.prototype
时,为什么实例null
仍然可以调用a
方法?
答案 0 :(得分:9)
您在创建实例Apple.prototype
之后更改a
引用。
此处更改引用并不会为现有实例更改它。
你也会找到
var a = new Apple();
Apple.prototype = {}; // some other object
a instanceof Apple; // false
即。因为我们已经改变了 Apple的继承链 a
不再被视为 Apple 。
如果您尝试进行Foo.prototype = null
检查,设置instanceof Foo
会导致 TypeError
更改对象的属性并不会将引用更改为该对象。例如
var foo = {},
bar = foo;
foo.hello = 'world';
foo === bar; // true
更改对象本身确实会更改参考
foo = {hello: 'world'};
foo === bar; // false
或者以更接近于如何从实例引用原型的方式编写
var Foo = {}, // pseudo constructor
bar = {},
baz = {};
var fizz = {}; // fizz will be our pseudo instance
Foo.bar = bar; // pseudo prototype
fizz.inherit = foo.bar; // pseudo inheritance
Foo.bar = baz; // pseudo new prototype
fizz.inherit === foo.bar; // false, instance inheritance points elsewhere
设置继承链的当前最佳做法不是使用new
,而是使用Object.create
Apple.prototype = Object.create(Fruit.prototype);
如果您需要在 Apple 实例上调用Fruit
构造函数,那么您可以
function Apple() {
// this instanceof Apple
Fruit.apply(this);
// ...
}
答案 1 :(得分:0)
我们必须了解线后面发生的事情
var a = new Apple();
JavaScript采用基于Prototype的编程作为其OOP风格。这意味着,它通过克隆以前的对象而不是通过实例化类来创建新对象。鉴于Gecko和Webkit JavaScript引擎,以下是“新”声明背后的内容:
var a = clone(Apple.prototype); // this is an analogy to memcpy() in C/C++
a.__proto__ = Apple.prototype; // useful for the instanceof checking
a.constructor = Apple; // a function
a.constructor(); // so "this" in the called function means "a"
现在, a.color 和 Apple.prototype.color 都是对位于地址的同一函数的引用,例如 0xABCD 因为值 0xABCD 已从 Apple.prototype 复制到 a 。因此,调用 a.color()将与地址 0xABCD 相关联,它与 Apple.prototype 无关,因此您可以自由地将 Apple.prototype 指定为null。
事实证明上面的 clone()函数实际上是众所周知的 Object.create()函数。 Object.create()还包含 __ proto __ 属性的分配。