日期:2014-05-16  浏览次数:20548 次

有趣的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.
直接改变prototype上的属性会影响所有的实例对象:
foo.prototype.x = "goodbye";
//now
f1.x  => "goodbye"
f2.x  => "goodbye";

?更多有趣的东西:

?沿着上图中的箭头走,你会发现javascript语言核心中的一些有趣的东西。(找个javascript console试试这些示例代码吧)

  • Function.__proto__指向Function.prototype。这使得:Function.constructor === Function,也就是说:Function是它自己的构造函数!
  • Object instanceof Object == true。这是因为:Object.__proto__.__proto__.constructor == Object。注意,跟Object instanceof Object不一样的是Foo instanceof Foo == false,这是因为:Foo并没有作为它原型链上的某个构造函数。
  • Function.prototype.toString是一个内置的函数,它有别于另外一个内置的函数:Object.prototype.toString
f1.toString() finds:
Object.prototype.toString

We get something like: [object ...]
?然而:
Foo.toString() first finds & uses:
Function.prototype.toString()
  
We get something like: [Function foo...]
?如果我们这样做:
delete Function.prototype.toString
Foo.t