面试必问!,网上各种各样的解释都有,还是自己总结一下,印象更深!
首先说说含义,这里引用MDN上的解释
当谈到继承时,JavaScript 只有一种结构:对象。每个实例对象(object)都有一个私有属性(称之为
__proto__)指向它的构造函数的原型对象(prototype)。该原型对象也有一个自己的原型对象(__proto__),层层向上直到一个对象的原型对象为null。根据定义,null没有原型,并作为这个原型链中的最后一个环节。几乎所有 JavaScript 中的对象都是位于原型链顶端的 [Object]的实例。
基于原型链的继承
首先先让我们来看一个"简单"的栗子:
// 让我们从一个函数里创建一个对象o,它自身拥有属性a和b的:
let fn = function () {
this.a = 1;
this.b = 2;
}
let o = new fn(); // {a: 1, b: 2}
// 在f函数的原型上定义属性
fn.prototype.b = 3;
fn.prototype.c = 4;
/*
不要在 fn 函数的原型上直接定义 fn.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} ---> {b:3, c:4} ---> 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
看完以后是不是觉得似懂非懂 ? 又或者已经一团糟了,不要慌 ! 我们看个简单的 !
function doSomething(){}
//给函数的原型对象添加新属性week
doSomething.prototype.week = 'Saturday'
//构造函数实例化
let example = new doSomething();
//实例添加prop属性
example.prop = 'example value'
example.__proto__ == doSomething.prototype //true
console.log(example);
最终打印的实例example如下图:
可以看到,当我们想要获取实例example的prop属性时,直接获取就行了,但是获取week属性时,实例中没有,那么浏览器就会通过example的__proto__即[[prototype]]属性往它的原型上去找,原型是谁呢? 构造函数doSomething的prototype.
那如果我们找一个不存在的属性a,先在实例example上找,没找到,通过example.__proto__往上层原型doSomething.prototype中查找,没找到?通过doSomething.prototype.__proto__再从Object.prototype中寻找,还是没找到,再往上!可是发现Object.prototype.__proto__是null,这时候就停止了查找并返回了undefined.
总结来说就是: example -->doSomething.prototype --> Object.prototype --> null这样的一条链式查询,就是原型链.
我是前端小萌新 薄凉,如果我的文章对你有帮助,请点个 赞👍🏻 支持我一下~