为了实现类似其他语言的继承的特性, JavaScript中的实现是使用 原型链
规则是这样的
在所有的对象上 都有一个 属性叫 [[prototype]], 这个属性属于隐藏属性, 即官方并没有给定它的属性名, 但目前浏览器上 给定的 属性名是 proto
当访问一个对象的某个属性时, 会先在 该对象自己的属性列表中查找, 如果没有 就到 proto 属性指向的对象中查找
var obj1 = {
prop1: "prop1 value"
};
var obj2 = {
prop2: "prop2 value"
};
这时, 获取 obj2 的 属性时, 只能获取 prop2 的值
obj2.__proto__ = obj1;
这时 再尝试 获取 obj2.prop1 时 就能拿到值
上面的代码在浏览器上是OK的
但是 正规的做法并不是 手动去 修改某个 对象的 proto 值, 更何况 proto 并不是一个标准的属性名称, 在 node.js 中可能没有
正规的做法是 先定义一个 函数
function Type1(){}
函数 也是对象, Type1 也有 proto 属性, 先不必理会这一点, 所有的函数 还有 另一个属性 名字是 prototype, 这个属性 是在定义 每一个函数时, 有Javascript 引擎创建的, 当用户调用 new Type1() 创建一个新的对象时, Javascript 引擎会将这个新对象的 proto 指向 Type1 的 prototype 属性
function Type1(){};
var obj1 = new Type1();
console.log(obj1.__proto__ === Type1.prototype)
输出:
true
这样 obj1 就间接有个 Type1.prototype 对象下的所有属性
function Type1(){};
Type1.prototype.prop1 = "prop1 value";
var obj1 = new Type1();
var obj2 = new Type1();
这时 obj1 和 obj2 都能访问到 prop1 的值
但是注意, 这里使用了类似 copy on write 的技术, 即当 写入 对象obj1 或 obj2 的 prop1 属性时,并没有覆盖掉 Type1.prototype 下的 prop1 属性, 而是会在 对象obj1 或 obj2 的拥有的属性中简历一个 prop1 属性
obj1.prop1 = "other value"
这时 只有 obj1 访问 prop1 属性时的值是 “other value”, 而 obj2 以及 Type1.prototype 的 prop1 属性并没有变
再解释一下 prototype 中的属性 和 this.写入的属性的差别
function Type1(){
this.prop1 = "prop1 value";
};
Type1.prototype.prop2 = "prop2 value";
var obj1 = new Type1();
这时 obj1 中已经直接有了 属性 prop1, 而 prop2 属性是间接的由 proto 访问到的(注: new 的时候由 Javascript 引擎 将 Type1 的 prototype 设置给了 obj1 的 proto)
从内存的占用空间上来说, prop1 是每个对象都有一份, 而 prop2 是所有对象共用一份
prototype 中的属性 非常适合 只读属性 和 函数, 因为没有必要再每个对象上都存储一个只读属性 和 函数变量, 所以 常规的做法是 将 只读属性和函数都定义在 Type1 的 prototype 上
另一种写法是使用 Object.create 方法, 该方法接受一个参数, 返回一个新建的对象, 并将这个对象的 proto 指向 给定的 参数对象
var Type1 = {
prop1: "prop1 value",
func1: function(){}
};
var obj1 = Object.create(Type1);
这时 obj1 中自己没有任何属性, 但它的 proto 属性 已经指向了 Type1