# (原型)继承-原型链
# (原型)继承
function Foo(name) {
this.name = name;
}
Foo.prototype.myName = function() {
return this.name;
};
var a = new Foo("a");
var b = new Foo("b");
a.myName(); // "a"
b.myName(); // "b"
2
3
4
5
6
7
8
9
10
js 模拟类行为的过程,通常被称作原型继承的机制
a 可以“继承”Foo.prototype 并访问 Foo.prototype 的 myName() 函数。实际是类和实例之间的关系:
# 典型的“原型风格”:
function Foo(name) {
this.name = name;
}
Foo.prototype.myName = function() {
return this.name;
};
function Bar(name, label) {
Foo.call(this, name);
this.label = label;
}
// 我们创建了一个新的 Bar.prototype 对象并关联到 Foo.prototype
Bar.prototype = Object.create(Foo.prototype);
// 注意!现在没有 Bar.prototype.constructor 了
// 如果你需要这个属性的话可能需要手动修复一下它
Bar.prototype.myLabel = function() {
return this.label;
};
var a = new Bar("a", "obj a");
a.myName(); // "a"
a.myLabel(); // "obj a"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
这段代码的核心部分就是语句 Bar.prototype = Object.create( Foo.prototype )。调用Object.create(..) 会凭空创建一个“新”对象并把新对象内部的 [[Prototype]] 关联到你指定的对象(本例中是 Foo.prototype)。换句话说,这条语句的意思是:“创建一个新的 Bar.prototype 对象并把它关联到 Foo.prototype”。
声明 function Bar() { .. } 时,和其他函数一样,Bar 会有一个 .prototype 关联到默认的对象,但是这个对象并不是我们想要的 Foo.prototype。因此我们创建了一个新对象并把原型 它关联到我们希望的对象上,直接把原始的关联对象抛弃掉。
# 注意
下面这两种方式是常见的错误做法,实际上它们都存在一些问题:
// 和你想要的机制不一样!
Bar.prototype = Foo.prototype;
// 基本上满足你的需求,但是可能会产生一些副作用 :(
Bar.prototype = new Foo();
2
3
4
Bar.prototype = Foo.prototype 并不会创建一个关联到 Bar.prototype 的新对象,它只是让 Bar.prototype 直接引用 Foo.prototype对象。因此当你执行类似 Bar.prototype.myLabel = ... 的赋值语句时会直接修改 Foo.prototype 对象本身。显然这不是你想要的结果,否则你根本不需要 Bar 对象,直接使用 Foo 就可以了,这样代码也会更简单一些。
Bar.prototype = new Foo() 的确会创建一个关联到 Bar.prototype 的新对象。但是它使用了 Foo(..) 的“构造函数调用”,如果函数 Foo 有一些副作用(比如写日志、修改状态、注册到其他对象、给 this 添加数据属性,等等)的话,就会影响到 Bar() 的“后代”,后果不堪设想。
因此,要创建一个合适的关联对象,我们必须使用 Object.create(..) 而不是使用具有副作用的 Foo(..)。这样做唯一的缺点就是需要创建一个新对象然后把旧对象抛弃掉,不能直接修改已有的默认对象。
// ES6 之前需要抛弃默认的 Bar.prototype
Bar.ptototype = Object.create(Foo.prototype);
// ES6 开始可以直接修改现有的 Bar.prototype
Object.setPrototypeOf(Bar.prototype, Foo.prototype);
2
3
4
# 原型链图解

# instanceof

- constructor : 指向实例的构造函数
- instanceof : 判断实例的 proto 和构造函数的 prototype(原型)或者原型的原型是否相等