JavaScript是一门基于原型继承的语言
——Douglas Crockford

函数的prototype属性

JS中的函数有一个属性prototype,指向其原型对象,其它类型的变量不存在该属性。
var a = 1, str = "中国", flag = true, obj = {}, func = function() {};
function add() {}
var test = new Function;
console.log(a.prototype);//undefined
console.log(str.prototype);//undefined
console.log(flag.prototype);//undefined
console.log(obj.prototype);//undefined
console.log(func.prototype);//Object{}
console.log(add.prototype);//Object{}
console.log(test.prototype);//Object{}
对象的__proto__属性
任何对象(除了undefined和null)都拥有一个属性,指向其原型对象,在大多数浏览器中,这个属性的名字是__proto__
var a = 1, str = "中国", flag = true, obj = {}, func = function() {};
function add() {}
var test = new Function;
console.log(a.__proto__ === Number.prototype);
console.log(str.__proto__ === String.prototype);
console.log(flag.__proto__ === Boolean.prototype);
console.log(obj.__proto__ === Object.prototype);
console.log(func.__proto__ === Function.prototype);
console.log(add.__proto__ === Function.prototype);
console.log(test.__proto__ === Function.prototype);
console.log(NaN.__proto__ === Number.prototype);
console.log(undefined.__proto__);//Uncaught TypeError: Cannot read property '__proto__' of undefined
console.log(null.__proto__);//Uncaught TypeError: Cannot read property '__proto__' of null
也就是说:
对象实例的
__proto__值 和 其构造函数的prototype值 指向了同一块内存区域,这两个属性完全相等
原型链
JS是基于原型继承的面向对象语言,这是它和C++、Java等其他面向对象语言的根本区别。网上流传的这张图很好地画出了JS家族的“族谱”。下面我结合这张图,谈谈我对图中每一根“链条”的理解~
注意:为了便于理解,建议把“函数”和“函数的原型”想象成内存中独立的两个块,函数的prototype指针,指向了“函数的原型”这个对象
f1对象是构造函数Foo的“实例”,因此f1.__proto__ =<mark> Foo.prototype- 函数
Foo的prototype属性指向了“函数的原型”,即Foo.prototype - 函数的原型有一个
constructor属性,指向函数本身,也就是说Foo.prototype.constructor </mark>= Foo。另外f1对象也有一个constructor属性,表示对象的构造函数,因此f1.constructor === Foo function Foo()的另一种声明方式是var Foo = new Function(),所以Foo.__proto__ === Function.prototypevar o1 = new Object(),因此o1.__proto__ === Object.prototype- 同2.
- 同3.
Object是JS内置的用于生成“对象类型的对象”的构造函数,因此function Object()可以理解为var Object = new Function(),也就是说Object是Function构造出来的实例对象,所以Object.__proto__ === Function.prototype- 这里有点难以理解,
Function是JS内置的用于生成“函数类型的对象”的构造函数,**8.**中的Object函数就是通过它new出来的。而我们知道,在JS的语法中,function AAA()可以改写为var AAA = new Function(),那么,function Function()可以改写成var Function = new Function()吗?答案是:可以!也就是说:如果把Function理解为一个对象,它的__proto__属性等于Function.prototype;如果把Function理解为一个函数,它的prototype属性当然也指向Function.prototype。所以,Function.__proto__ =<mark> Function.prototype! - 同2.
- 同3.
- 除了(构造)函数
Object以外,JS中任何(构造)函数的原型都有一个__proto__属性指向Object.prototype这个原型。而(构造)函数Object的原型直接指向Object.prototype,中间不需要通过__proto__属性相连。因此Foo.prototype.__proto__ </mark>= Object.prototype、Function.prototype.__proto =<mark> Object.protype、Object.prototype </mark>= Object.prototype(废话!) - 同12.
Object.prototype可以被认为是JS世界中一切的老祖宗,因为一切对象都继承自她,一切对象往上追溯若干个__proto__都会到达Object.prototype这里。那么问题是,Object.prototype也是一个对象,她的__proto__属性应该是她的“构造函数的原型”,那么这个原型是什么呢?我们试一下:
Object.prototype.__proto__ === null
**WTF?!(黑人问号脸)**老祖宗是特么从石头缝里蹦出来的?!不过这到让JS蒙上了一层神(装)秘(逼)色彩。
我们翻过了一座又一座山头,到头来发现山的那边还是一座山。
我们以为故事的结尾有一只精灵藏匿在这语言的最核心,最后发现,这语言的核心竟是一场空。
–END–