1994年,网景公司(Netscape)发布了Navigator浏览器0.9版,但是刚开始的Js没有继承机制,更别提像同时期兴盛的C++和Java这样拥有面向对象的概念。在实际的开发过程中,工程师们发现没有继承机制很难解决一些问题,必须有一种机制能将所有的对象关联起来。Brendan Eich鉴于以上情况,但不想把Js设计得过为复杂,于是引入了new关键词 和 constructor构造函数来简化对象的设计,引入了prototype函数对象来包含所有实例对象的构造函数的属性和方法,引入了proto和原型链的概念解决继承的问题。
介绍
__proto__
引用《JavaScript权威指南》的一段描述:
Every JavaScript object has a second JavaScript object (or null ,
but this is rare) associated with it. This second object is known as a prototype, and the first object inherits properties from the prototype.
翻译出来就是每个JS对象一定对应一个原型对象,并从原型对象继承属性和方法。好啦,既然有这么一个原型对象,那么对象怎么和它对应的?
对象__proto__
属性的值就是它所对应的原型对象:
var a = {x: 1};
var b = new Object();
a.__proto__ === Object.prototype // true
b.__proto__ === Object.prototype // true
one.toString === one.__proto__.toString // true
上面的代码应该已经足够解释清楚__proto__
了。好吧,显然还不够,或者说带来了新的问题:Object.prototype
是什么?凭什么说one
和two
的原型就是Object.prototype
?
prototype
首先来说说prototype
属性,不像每个对象都有__proto__
属性来标识自己所继承的原型,只有函数才有prototype
属性。
为什么只有函数才有prototype
属性?ES规范就这么定的。
开玩笑了,其实函数在JS中真的很特殊,是所谓的一等公民。JS不像其它面向对象的语言,它没有类(class
,ES6引进了这个关键字,但更多是语法糖)的概念。JS通过函数来模拟类。
当你创建函数时,JS会为这个函数自动添加prototype
属性,值是空对象 值是一个有 constructor 属性的对象,不是空对象。而一旦你把这个函数当作构造函数(constructor
)调用(即通过new
关键字调用),那么JS就会帮你创建该构造函数的实例,实例继承构造函数prototype
的所有属性和方法(实例通过设置自己的__proto__
指向承构造函数的prototype
来实现这种继承)。
小结
1.每个函数对象都有一个 prototype 属性,这个属性就是函数的原型对象。
2.原型链是JavaScript实现继承的重要方式,原型链的形成是真正是靠proto 而非prototype
3.原型链所形成的过程可以以下解释:
arr ---> Array.prototype ---> Object.prototype ---> null
js所说的原型链,就是层层向上查找,最后没有时就返回undefined,
使用new创建一个的对象时,函数对应的prototype方法,数据的prototype方法的上一层(prototype.proto)就是object对象的prototype方法。直接的可以理解为:
var 对象 = new 函数()
对象.__proto__ === 函数.prototype
而.__proto一层一层的指向就可以被称为原型链。
由此也可以引出以下几个推论:
// 推论
var number = new Number()
number.__proto__ = Number.prototype
Number.__proto__ = Function.prototype // 因为 Number 是 Function 的实例
var object = new Object()
object.__proto__ = Object.prototype
Object.__proto__ = Function.prototype // 因为 Object 是 Function 的实例
var function = new Function()
function.__proto__ = Function.prototype
Function.__proto__ == Function.prototye // 因为 Function 是 Function 的实例!
探讨
我们知道JS是单继承的,Object.prototype
是原型链的顶端,所有对象从它继承了包括toString
等等方法和属性。
Object
本身是构造函数,继承了Function.prototype
;Function
也是对象,继承了Object.prototype
。这里就有先有鸡和先有蛋的问题:
Object instanceof Function // true
Function instanceof Object // true
什么情况下会出现鸡和蛋的问题呢?就是声明一个包含所有集合的集合啊!好了,你们知道这是罗素悖论,但并不妨碍PL中这样设计。
那么具体到JS,ES规范是怎么说的?
Function本身就是函数,
Function.__proto__
是标准的内置对象Function.prototype
。
Function.prototype.__proto__
是标准的内置对象Object.prototype
。
参考链接:
1.JavaScript深入之从原型到原型链
网友评论