一张图解释清楚JS中的原型、原型链(高频面试考点)
原型 原型链
下面这张图是一位小伙伴面试前端岗位,被问到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
至此,文章开头的原型原型链图,解释(推导)完毕。
(完)
相关文章
- js控制30秒自动页面跳转,带读秒
- JS跳转代码_js中跳转页面路径
- js函数柯里化-面试手写版
- 刷完15道js版dp题,面试再也不怕了
- JS面试、技巧总结点二-匿名函数详解
- js手写题汇总(面试前必刷)
- Vue.js – 引入外部 JS 文件
- js函数柯里化-面试手写版_2023-02-27
- 前端面试指南之JS面试题总结2
- 前端JS、CSS版本控制
- vue.js客服系统实时聊天项目开发(十九)使用正则将消息格式替换为产品卡片信息
- JS模块化—CJS&AMD&CMD&ES6-前端面试知识点查漏补缺_2023-03-13
- JS的内置对象和方法(允许自定义对象)详解编程语言
- 创建JS文件:在Linux下实现自动化任务(linux创建js文件)
- 使用JS控制Oracle数据库的更新(js控制oracle更新)
- js输入中文效果
- 自己的js工具Event封装
- 地址栏传递中文参数乱码在js里用escape转码
- JS鼠标滑过图片时切换图片实现思路
- 在页面中js获取光标/鼠标的坐标及光标的像素坐标
- js获取html页面节点方法(递归方式)
- javascript文件中引用依赖的js文件的方法
- JSP加载JS文件不起作用的有效解决方法
- js使用递归解析xml