一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第13天,点击查看活动详情
前言
javascript高级程序设计 这样描述原型:
每个函数都会创建一个
prototype
属性,这个属性是一个对象,包含应该由特定引用类型的实例共享的属性和方法。实际上,这个对象就是通过调用构造函数创建的对象的原型。使用原型对象的好处是,在它上面定义的属性和方法都可以被对象实例共享。原来在构造函数中直接赋给对象实例的值,可以直接赋值给它们的原型。
JavaScript 的原型和原型链一直是前端初学者的 "绊脚石",看文档理解起来生涩难懂,所以我采用图文并茂的方式来谈谈我的理解,本文只代表我个人见解,如果有错误的,欢迎大家指出😄 ~~。
原型
每个函数都有一个
prototype
属性。每个对象都存在
__proto__
属性,用来描述对象的原型。
先来看一段代码:
function Jackson () {}
Jackson.prototype.name = '杰克逊';
Jackson.prototype.age = '18';
let jack = new Jackson();
console.log('jack:', jack);
console.log('name:', jack.name);
上面代码打印的结果:
为什么会打印这些呢? 首先我们 new
了一个原生构造函数 Jackson()
,把他赋值给一个名字叫做 jack
的实例, jack
里没有 挂载 任何的东西(函数、属性等),但是它有个 Prototype
对象,里面有 age
和 name
属性,还有一个 constructor
指向的是 Jackson()
,为什么会这样呢? 我明明没有添加这个对象啊,它是怎么出现的? 因为 函数 Jackson()
和 jack
的 __proto__
都指向 Jackson.prototype
这个对象,这是 js
自带的属性。
下面画一张图能够直观的看清它们之间的关系:
图中的关系可以解释为,每个构造函数都有一个 __proto__
指向它的 原型对象
,原型对象中有一个 constructor
属性指向构造函数,而 new
出来的 实例
内部有个 __proto__
的属性也指向 构造函数的 原型对象
。
原型链
当我们访问一个对象的属性,如果在这个对象的内部找不到该属性,那么他就会去他的原型对象上找,这个原型对象又会有自己的原型,一直往上找,直到尽头
Object.portotype
,这就是原型链的核心。所有的原型对象
prototype
最终都会指向Object.prototype
,而Object.prototype
的__proto__
指向null
。
__proto__
又叫做隐式原型
,也可以理解为一根看不见的绳子,绑住两个物体。
画一张图供大家参考:
例子
说了那么多还不如写几道题目巩固一下知识,手底下见章~~
例题一:
先来看看《我的大怨种面试官》出的题:
// 看代码说结果
function foo() {}
const bar = new foo()
console.log(bar.__proto__)
console.log(bar.__proto__.__proto__)
console.log(bar.__proto__.__proto__.__proto__)
console.log(bar.__proto__.__proto__.__proto__.__proto__)
console.log(foo.prototype)
console.log(foo.prototype.prototype)
console.log(foo.prototype.prototype.prototype)
这就有点意思了,哼,就这?画一张图就清清楚楚了。
console.log(bar.__proto__)
打印结果为:
{constructor: ƒ}
console.log(bar.__proto__.__proto__)
打印结果为:
{constructor: ƒ, __defineGetter__: ƒ...}
console.log(bar.__proto__.__proto__.__proto__)
打印结果为:
null
console.log(bar.__proto__.__proto__.__proto__.__proto__)
纳尼?
null.__proto__
哪还有东西?肯定会打印报错,Cannot read properties of null (reading '__proto__')
结果不出所料。
console.log(foo.prototype)
打印结果为:
foo.prototype
跟第一个console.log
结果一样。
console.log(foo.prototype.prototype)
我擦?foo的原型对象的原型对象? 有这种东西?肯定报错了。结果查看一下打印结果是
undefined
,什么情况?首先我们知道foo.prototype
是一个 对象,说明它具有对象的特性(重点,要考的),于是 我们要思考一个问题 JavaScript 中什么情况下会返回 undefined 值? ,哦,原来如此,在JavaScript
中 对象属性名不存在时,显示undefined,这就可以解释为什么会打印undefined
了。
大家可以想象成下面的代码,有一个叫 fooPrototype
的对象,当我们试图获取这个对象里的某一个不存在的属性时,它会返回 undefined
。
let fooPrototype = {
}
console.log(fooPrototype.prototype) // undefined
还有最后一个:
console.log(foo.prototype.prototype.prototype)
同理,把上述代码改造一下:
let fooPrototype = {
}
console.log(fooPrototype.prototype.prototype)
// Cannot read properties of undefined (reading 'prototype')
这里会出现报错了。提示 Cannot read properties of undefined (reading 'prototype')
因为 fooPrototype.prototype
返回是一个 undefined
,它是一个基本数据类型,你想获取一个基本数据类型里的属性,就会出现报错。
总结
以上就是本次分享的全部内容~~
如果觉得文章写得不错,对你有所启发的,请不要吝啬 点个 赞
和 关注
并在 评论区
留下你宝贵的意见哦~~😃