有趣的JavaScript原型链
原文地址:http://www.mollypages.org/misc/js.mp
几个有意思的知识点:
- 所有的实例对象都继承了创建它们的构造函数的原型对象。
- Mozilla/Konqueror浏览器实现了一个特殊的__proto__属性来指向构造函数(用来创建属于该原型对象类型的实例对象的函数)的原型对象。
- 别去纠结有没有这么一个小小的__proto__属性,我们的思路就是要所有的实例对象能够使用它们的构造函数所指向的原型对象。这个属性是prototype,它是JavaScript标准的一部分。prototype对象默认都有一个constructor属性反向指向了以该prototype对象作为原型的构造函数。
- prototype对象只为构造函数创建出来的实例对象继承属性所用,构造函数自己却并不使用它(但既然该构造函数自己也是一个对象,那么它也会继承它的构造函数的原型,一般是javascript系统的Function对象)。
function Foo() { } ;
var f1 = new Foo();
Foo.prototype.x = "hello";
f1.x //=> hello
Foo.x //=> undefined注意,我们使用Foo.prototype来为所有Foo函数创建出来的实例对象设置属性。我们没有使用f1.prototype来为f1设置属性,请记住,这一点非常的重要!- 默认的prototype对象可以被用户创建的对象替换掉。这样做的话,我们必须重复javascript运行时在幕后对默认的prototype对象所做的那样去手动设置constructor属性。
function foo() { } ; var f1 = new foo();
f1.constructor === foo.prototype.constructor === foo
//replace the default prototype object
foo.prototype = new Object();
//now we have:
f1.constructor === foo.prototype.constructor === Object
//so now we say:
foo.prototype.constructor = foo
//all is well again
f1.constructor === foo.prototype.constructor === foo- 每一个的prototype对象自己都是由Object()函数(默认情况下)创建而来,所以prototype有它自己的原型那就是Object.prototype。因此无论什么类型的实例最终都会继承Object.prototype对象的属性。
- 所有的对象会自动从原型链上读取属性,就好像这些属性就定义在这些对象中一样。
function foo() { }
f1 = new foo();
f2 = new foo();
foo.prototype.x = "hello";
f1.x => "hello"
f2.x => "hello";
f1.x = "goodbye"; //setting f1.x hides foo.prototype.x
f1.x => "goodbye" //hides "hello" for f1 only
f2.x => "hello"
delete f1.x
f1.x => "hello"; //foo.prototype.x is visible again to f1.