前戏:本文讨论的内容对 javascript 和 node.js 都适用,所以下面统称为 js 。
最近因为工作和学习的原因,接触了一些以前看过和没看过的资料,所以记下来,希望大家可以更好地理解 js 和原型 (prototype) 。
首先要牢记这几个点:
- js 是面向对象的编程语言
- js 是基于原型 (prototype) 的
- js 并没有实现传统的类 (class) 系统
最会引起困惑的应该是第二点。怎么理解呢?js中的每一个对象都有一个内置的属性叫 __proto__
,也就是这个对象的原型 (prototype) ,这个原型也是一个js的对象。如果我试图访问 object.prop
,而 object
本身又没有 prop
这个属性,js就会去 object
的原型对象 (project.__proto__
) 上去找;如果这个原型对象里面依然没有 prop
,那么js就会去这个原型对象的原型对象 (object.__proto__.__proto__
) 里面去找;直到这个原型对象的原型对象的…的原型对象是 null 为止。
其实类继承 (Class Based Inheritance) 和原型继承 (Prototype Based Inheritance) 其实都是为了满足 OOP 。简单一点来说,我们希望子类的对象可以继承父类定义的一些成员,增强代码的可重用性和抽象层级。
下面这段代码来自于 Douglas Crockford ,实现了最简单的原型继承:
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
var obj = {a:1, b:2};
var newObj = object(obj);
newObj.a //=> 1
newObj.__proto__ === obj //=>true
//此时,newObj.a 并不是 newObj 自己的属性,而是顺着原型链找到的 obj 的属性
newObj.hasOwnProperty('a') //=>false
obj.hasOwnProperty('a') //=>true
newObj.a === obj.a //=>true
object
函数接受一个对象作为参数,生成一个继承该对象的新对象。当我们试图访问新对象的某个不存在的属性时,js会沿着原型链找到旧对象,然后在旧对象里面想办法找到该属性。