zl程序教程

您现在的位置是:首页 >  后端

当前栏目

一张图解释清楚JS中的原型、原型链(高频面试考点)

JS面试 解释 原型 高频 一张 清楚 考点
2023-06-13 09:11:05 时间

原型 原型链

下面这张图是一位小伙伴面试前端岗位,被问到JavaScript的原型和原型链的知识点,没有答出来,面试结束之后,HR发给他的。我觉得这张图把prototype__proto__解释的很好,在这里分享给大家,并为大家推导一下整幅图:

1. 名称

prototype:原型

__proto__:原型链

2. 从属关系

prototype从属于函数,是函数的一个原型属性(也叫prototype属性),是一个对象__proto__是对象的属性,它本身也是一个对象。对象的__proto__属性保存着创建该对象的构造函数的prototype属性。每个对象(除了null)都默认有__proto__属性。

从属关系很重要,一定要搞明白!

3. 验证从属关系

上一期推文我们已经知道,用class关键字创建出来的类其实也是一个函数:

class Person {}
console.log(typeof Person); // function

既然类是函数,那么它一定有自己的prototype属性:

console.log(Person.prototype); // {constructor: ƒ}

用Person类创建一个对象,验证该对象有__proto__属性,并且根据从属关系,验证等于其构造函数(此处为Person类)的prototype属性:

const p = new Person();
console.log(p.__proto__); // {constructor: ƒ}
console.log(p.__proto__ === Person.prototype); // true

4. 解释一下constructor属性

延用上面的例子,我们打印p.__proto__对象,会看到它的第一个属性就是constructor属性,并且这个constructor属性指向创建这个对象的类:

我们展开constructor属性:

发现constructor属性里面还有一个prototype属性,而且这个prototype属性刚好等于p.__proto__,如果我们再展开它:

……

经过不断的展开、观察,不难发现,对象p.__proto__constructor属性指向构造它的类,而这个constructor属性的prototype属性又等于p.__proto__,也就是说,constructor属性和prototype属性是一对相反的方向,代码验证:

console.log(p.__proto__.constructor); // class Person {}
console.log(p.__proto__.constructor.prototype); // {constructor: ƒ}
console.log(p.__proto__.constructor.prototype.constructor); // class Person {}
console.log(p.__proto__.constructor.prototype.constructor.prototype); // {constructor: ƒ}
……

所以根据constructor属性,我们可以推测是什么构造出来的这个对象。

5. 验证一个想法

有了上边的基础,我们打印一下Person.prototype.__proto__

我们发现,Person.prototype.__proto__constructor属性指向的是Object,那么这段代码自然自然成立:

console.log(Person.prototype.__proto__.constructor === Object); // true
// 有了刚刚讲过的constructor属性的经验,我们可以得到:
console.log(Person.prototype.__proto__ === Object.prototype); // true

我们只需要再记住JS中这样的一个规定:

Object.prototype.__proto__ = null; // 原型链的最尾端为null

我们就基本解释左半张图:

6. 函数也是对象

相信大家都知道,在JS中,一切皆为对象。函数也不例外,在JS中,每一个函数实际上都是一个函数对象。既然知道了函数也是对象,函数也一定有__proto__属性。延用上边的例子:

console.log(typeof Person); // function
console.log(Person.__proto__); // ƒ () { [native code] }

展开Person.__proto__

因为在JS的底层,Person类是由new Function()而来,即:

console.dir(Person.__proto__.constructor); // ƒ Function()

则:

console.dir(Person.__proto__ === Function.prototype); // true

又因为Function的类型也是函数:

console.log(typeof Function); // function

所以我们可以推出:

console.dir(Function.__proto__ === Function.prototype); // true

之前说过,一个对象的__proto__属性和prototype属性均为对象,且对象默认情况下都有自己的__proto__属性,我们打印一下Function.prototype.__proto__

就是说:

console.log(Function.prototype.__proto__.constructor === Object); // true

从而得到:

console.log(Function.prototype.__proto__.constructor.prototype === Object.prototype); // true

抵消掉constructor.prototype之后得到:

console.log(Function.prototype.__proto__ === Object.prototype); // true

至此,文章开头的原型原型链图,解释(推导)完毕。

(完)