前端八股之JS的原型链
1.原型的定义
每一个对象从被创建开始就和另一个对象关联,从另一个对象上继承其属性,这个另一个对象
就是 原型。
当访问一个对象的属性时,先在对象的本身找,找不到就去对象的原型上找,如果还是找不到,就去对象的原型(原型也是对象,也有它自己的原型)的原型上找,如此继续,直到找到为止,或者查找到最顶层的原型对象中也没有找到,就结束查找,返回undefined
。
这条由对象及其原型组成的链就叫做原型链。
总结:
- 原型存在的意义就是组成原型链:引用类型皆对象,每个对象都有原型,原型也是对象,也有它自己的原型,一层一层,组成原型链。
- 原型链存在的意义就是继承:访问对象属性时,在对象本身找不到,就在原型链上一层一层找。说白了就是一个对象可以访问其他对象的属性。
- 继承存在的意义就是属性共享:好处有二:一是代码重用,字面意思;二是可扩展,不同对象可能继承相同的属性,也可以定义只属于自己的属性。
2.原型链定义
每个对象都有一个内部属性 [[Prototype]]
(可通过 __proto__
访问),这个[[Prototype]]
指向它的原型对象(prototype
),这个原型对象也有自己的 __proto__
,一直向上查找,最终到达终点null
,形成原型链。
总结:
- 对象有
__proto__
属性,函数有__proto__
属性,数组也有__proto__
属性,只要是引用类型,就有__proto__
属性,指向其原型。 - 只有函数有
prototype
属性,只有函数有prototype
属性,只有函数有prototype
属性,指向new
操作符加调用该函数创建的对象实例的原型对象。
实例代码
function Person(name) {this.name = name;
}Person.prototype.sayHello = function() {console.log("Hello, I'm " + this.name);
};const p = new Person("Alice");p.sayHello(); // 从 p 找不到 sayHello,顺着原型链找到 Person.prototype
p --> Person.prototype --> Object.prototype --> null
-
p.__proto__ === Person.prototype
-
Person.prototype.__proto__ === Object.prototype
-
Object.prototype.__proto__ === null
3.constructor
构造函数都有一个prototype
属性,指向使用这个构造函数创建的对象实例的原型对象。
这个原型对象中默认有一个constructor
属性,指回该构造函数。
Person.prototype.constructor === Person // true
4.应用
①.手写实现instanceof
function instanceof2(L, R) {// 获取 R 的 prototype.//R 是构造函数,我们要找的是它的 .prototype,这是构造出来对象的原型。let RP = R.prototype;// 获取 L 的原型//取 L 的原型(注意是 __proto__,而不是 prototype),它表示当前对象的内部原型链引用。L = L.__proto__;// 遍历 L 的原型链while (true) {if (L === null) { // 到头了都没找到,说明不是return false;}// 🔽 插入这行代码if (L === RP) { // 找到了原型链中有构造函数的 prototypereturn true;}L = L.__proto__; // 继续向上查找原型链}
}
instanceof
的本质:判断某对象的原型链上是否能找到构造函数的.prototype
。-
__proto__
是对象的内部原型引用。 -
可以用
Object.getPrototypeOf(obj)
来代替__proto__
(更标准)。