JS里原型、原型链以及instanceof和new实现

JS 对象的 __proto__

  • 所有的引用类型(数组、对象、函数),都有一个__proto__属性,属性值是一个普通的对象
  • 所有的函数,都有一个 prototype 属性,属性值也是一个普通的对象
  • 所有的引用类型(数组、对象、函数),__proto__属性值指向它的构造函数的 prototype 属性值

:ES6 的箭头函数没有prototype属性,但是有__proto__属性。

1
2
3
4
const obj = {};
// 引用类型的 __proto__ 属性值指向它的构造函数的 prototype 属性值
console.log(obj.__proto__ === Object.prototype); // output: true

原型

题目:如何理解 JS 中的原型?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 构造函数
function Foo(name, age) {
this.name = name;
}
Foo.prototype.alertName = function() {
alert(this.name);
};
// 创建示例
var f = new Foo("zhangsan");
f.printName = function() {
console.log(this.name);
};
// 测试
f.printName();
f.alertName();

但是执行alertName时发生了什么?这里再记住一个重点 当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的**__proto__(即它的构造函数的prototype**)中寻找,因此f.alertName就会找到Foo.prototype.alertName

原型链

题目:如何 JS 中的原型链?

以上一题为基础,如果调用f.toString()

  1. f试图从__proto__中寻找(即Foo.prototype),还是没找到toString()方法。
  2. 继续向上找,从f.__proto__.__proto__中寻找(即Foo.prototype.__proto__中)。因为Foo.prototype就是一个普通对象,因此Foo.prototype.__proto__ = Object.prototype
  3. 最终对应到了Object.prototype.toString
    这是对深度遍历的过程,寻找的依据就是一个链式结构,所以叫做“原型链”。

instanceof 实现

instanceof是通过原型链来进行判断的,所以只要不断地通过访问__proto__,就可以拿到构造函数的原型prototype。直到null停止。

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
/**
* 判断left是不是right类型的对象
* @param {*} left
* @param {*} right
* @return {Boolean}
*/
function instanceof2(left, right) {
let prototype = right.prototype;
// 沿着left的原型链, 看看是否有何prototype相等的节点
left = left.__proto__;
while (1) {
if (left === null || left === undefined) {
return false;
}
if (left === prototype) {
return true;
}
left = left.__proto__;
}
}
/**
* 测试代码
*/
console.log(instanceof2([], Array)); // output: true
function Test() {}
let test = new Test();
console.log(instanceof2(test, Test)); // output: true

new 操作符实现

做之前,得懂:

  1. apply的用法
  2. __proto__和函数prototype属性的关系

实现方法:

1
2
3
4
5
6
7
8
9
10
function mynew(Func, ...args) {
// 1.创建一个新对象
const obj = {}
// 2.新对象原型指向构造函数原型对象
obj.__proto__ = Func.prototype
// 3.将构建函数的this指向新对象
let result = Func.apply(obj, args)
// 4.根据返回值判断
return result instanceof Object ? result : obj
}