# JS:prototype chain
# 定义
每个JS对象都有一个prototype,这个prototype又有自己的prototype,以此类推直到某个对象的prototype 是null为止,一个一个串成链
# 获取
- ECMA2015:Object.getPrototypeOf(),对应的是Object.setPrototypeOf()
- 大部分浏览器实现:Object._proto_
# 注意点
- 函数的func.prototype表示的是当此函数作为构造器时,构造的对象对应的prototype链接
let f1 = function () {
this.a = 1;
this.b = 2
}
let obj1 = new f1();
console.log(Object.getPrototypeOf(obj1));// f1{}
console.log(obj1.a);//1
console.log(obj1.c);// undefined
f1.prototype.c = 3;
console.log(obj1.a);//1
console.log(obj1.c);//3
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 继承到的“方法”
当一个对象继承到的方法被执行时,方法内部的this指向的是当前继承到方法的对象
let animal = {
name: 'animal',
getName: function () {
return this.name;
},
getNameArrow: () => {
return this.name
}
}
console.log(animal.getName()); // animal
console.log(animal.getNameArrow()); // undefined,因为箭头函数定义时的上下文为全局作用域
let cat = Object.create(animal);
cat.name = 'cat'
console.log(cat.getName()); // cat
console.log(cat.getNameArrow()); // undefined,因为箭头函数定义时的上下文为全局作用域
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 使用原型链
函数原型作为构造器
function animal() {} animal.prototype.name = 'noname' let cat = new animal() console.log(cat.name);// noname
1
2
3
4函数原型上的属性会被以函数作为构造器的实例类获取
function gen1() {}
gen1.prototype.foo = "bar"
let gen2 = new gen1();
gen2.prop = "some prop"
console.log(`gen2.prop:${gen2.prop}`);
console.log(`gen2.foo :${gen2.foo}`);
console.log(`gen1.prop:${gen1.prop}`);
console.log(`gen1.foo :${gen1.foo}`);
console.log(`gen1.prototype.prop:${gen1.prototype.prop}`);
console.log(`gen1.prototype.foo:${gen1.prototype.foo}`);
//
gen2.prop:some prop
gen2.foo :bar
gen1.prop:undefined
gen1.foo :undefined
gen1.prototype.prop:undefined
gen1.prototype.foo:bar
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 创建对象的几种方法及相关原型链
语法构造器
// 直接构造的对象原型链o1 ---> Object.prototype ---> null let o1 = { a: 1 } console.log(o1.__proto__ === Object.prototype); // true // 函数的原型为Function.prototype let f1 = function () {} console.log(f1.__proto__ === Function.prototype); // true // 数组的原型为Array.prototype,Array.prototype的原型为Object.prototype let a1 = ['1asdf', 'asdf'] console.log(a1.__proto__ === Array.prototype); // true console.log(a1.__proto__.__proto__ === Object.prototype);// true
1
2
3
4
5
6
7
8
9
10
11
12使用构造器:即new 后加函数
function animal() { this.name = 'ani' } let cat = new animal(); console.log(cat.__proto__ === animal.prototype); // true console.log(animal.prototype.__proto__ === Object.prototype); // true
1
2
3
4
5
6Object.create()
let o = { name: 'ooo' } let o2 = Object.create(o) console.log(o2.__proto__ === o);// true
1
2
3
4
5class关键词
'use strict' class animal { constructor(age) { this.age = age; } } class cat extends animal { constructor(age, name) { super(age) this.name = name } get desc() { return this.name + ':' + this.age } set realName(catN) { this.name = catN } } let pet = new cat(12, 'kitty'); console.log(pet.desc);// kitty:12 pet.realName = 'mojo' console.log(pet.desc);// mojo:12
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 各种方式优劣势比较
# 关注Performance
寻找属性时,在没找到前总是会沿着原型链往上找
若整条链上没有这个属性,则总会走完完整的原型链
若不想从原型链往上tranverse,可以调用obj.hasOwnProperty()
let o = { name: 'ooo' } let o2 = Object.create(o) console.log(o2.__proto__ === o); // true console.log(o2.hasOwnProperty('name')); // false
1
2
3
4
5
6