Javascript-Basic-原型链
文章目录

原型链对象

一句话描述原型链: 遍历一个实列的属性时,先遍历实列对象上的属性,再遍历它的原型对象,一直遍历到 Object

创建对象的三种方法

直接创建

1
2
3
4
var obj11 = {
name: 'qianguyihao'
};
var obj12 = new Object(name: 'qianguyihao'); // 这种方法跟上面一行效果一样。

构造函数

1
2
3
4
var M = function(name) {
this.name = name;
}
var obj3 = new M('smyhvae');

Object.Create()

1
2
3
4
var p = {
name: 'smyhvae'
};
var obj3 = Object.create(p); //此方法创建的对象,是用原型链连接的, p 是 obj3 的原型

new 关键字做了什么操作

  1. 创建了一个对象 obj
  2. 构造函数中的 this 指向这个新对象 obj
    • 构造函数中会有一些 this.a = a , 这样就可以将传入的 a 通过 this 传给这个新对象, 通过操作 this 给 obj 添加属性
  3. 连接 prototype, 设置 obj 的 __proto__ 指向构造函数的 prototype
    • 所以修改 prototype 可以影响到所有的实例
  4. 如果构造函数没有额外返回, 那么返回这个处理过的 obj

原型链

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function Person(name) {
this.name = name;
}

var personOne = new Person("a");
var personTwo = new Person("b");

/* 我们可以在实例创建之后修改对应的原型链,所有的修改都会反应到对应的实例里面。*/

Person.prototype.sayName = function() {
console.log(this.name);
}

personOne.sayName(); // 输出 "a"
personTwo.sayName(); // 输出 "b"

console.log(personOne.__proto__ === Person.prototype); // true
console.log(personTwo.__proto__ === Person.prototype); // true

console.log(personOne.constructor === Person); //true
console.log(personTwo.constructor === Person); //true
console.log(Person.prototype.constructor === Person); //true

console.log(Person.constructor); //function Function(){}
console.log(Person.__proto__.__proto__); // Object{}

修改原型链会出现的情况.

如果让原型对象指向另一个类型的实例….. 有趣的事情便发生了.
即:

1
2
Var instance1 = new Constructor1();
constructor1.prototype = instance2;

那么如果使用一些方法或者属性, 首先会去找 instance1, 然后找 instance1.__proto__ (即 constructor1.prototype 也就是 instance2 )
如果 instance2 也没有这玩意还会去找 Object 的 原型对象

修改原型链的变化

附录

原型链继承的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/* 让我们从一个自身拥有属性 a 和 b 的函数里创建一个对象 o:*/
let f = function() {
this.a = 1;
this.b = 2;
}
/* 这么写也一样
function f() {
  this.a = 1;
  this.b = 2;
}
*/
let o = new f(); // {a: 1, b: 2}

// 在 f 函数的原型上定义属性
f.prototype.b = 3;
f.prototype.c = 4;

// 不要在 f 函数的原型上直接定义 f.prototype = {b:3,c:4};这样会直接打破原型链
// o.[[Prototype]] 有属性 b 和 c
//  (其实就是 o.__proto__ 或者 o.constructor.prototype)
// o.[[Prototype]].[[Prototype]] 是 Object.prototype.
// 最后 o.[[Prototype]].[[Prototype]].[[Prototype]]是 null
// 这就是原型链的末尾,即 null,
// 根据定义,null 就是没有 [[Prototype]]。

// 综上,整个原型链如下: 

// {a:1, b:2} > Object.prototype---> null

console.log(o.a); // 1
// a 是 o 的自身属性吗?是的,该属性的值为 1

console.log(o.b); // 2
// b 是 o 的自身属性吗?是的,该属性的值为 2
// 原型上也有一个'b'属性,但是它不会被访问到。
// 这种情况被称为"属性遮蔽 (property shadowing)"

console.log(o.c); // 4
// c 是 o 的自身属性吗?不是,那看看它的原型上有没有
// c 是 o.[[Prototype]]的属性吗?是的,该属性的值为 4

console.log(o.d); // undefined
// d 是 o 的自身属性吗?不是,那看看它的原型上有没有
// d 是 o.[[Prototype]] 的属性吗?不是,那看看它的原型上有没有
// o.[[Prototype]].[[Prototype]] 为 null,停止搜索
// 找不到 d 属性,返回 undefined