JS中的原型链(超清晰理解)
什么是原型链
原型链,所有的原型构成了一个链条,这个链条我们称之为原型链(prototype chain)。
原型链的案例
如果我们执行下面这段代码,因为没有定义address这个属性,程序结果理所当然的是undefined。
let obj = {
name : 'harry',
age:18
}
console.log(obj.address); //undefined
这个时候经历了什么呢?JS引擎线从Obj.address里寻找,发现没有找到,然后接着去找obj.__ proto __ 里面寻找,发现还是没找到,所以结果为undefined。我们可以给obj.__ proto __ 赋值
let obj = {
name : 'harry',
age:18
}
obj.__proto__ = {
address:'上海'
}
console.log(obj.address); //上海
或者这样
obj.__proto__ = {
//这里一定要开辟一个空间,不能直接写obj.__proto__.__proto__ = {}
}
obj.__proto__.__proto__= {
address:'上海'
}
console.log(obj.address); //上海
接着套娃
let obj = {
name : 'harry',
age:18
}
obj.__proto__ = {
}
obj.__proto__.__proto__= {
}
obj.__proto__.__proto__.__proto__= {
address:'上海'
}
console.log(obj.address); //上海
js引擎会顺着这些原型不断的往上找,直到address这个属性。这些原型构成了原型链。
原型链的顶层
那如果我们一直找,哪里是头呢?先看一段代码。
let obj = {
name : 'harry',
age:18
}
console.log(obj.__proto__); //[Object: null prototype] {}顶层原型
console.log(obj.__proto__.__proto__) //null
这里的Object就是顶层原型,如果再往上找,结果就是null了(已经到了末尾,这个链表指向为null)。
Object是从哪来的
创建对象有如下的两种用法,Object也就来自于这里
var obj1 = {} //创建了一个对象
var obj2 = new Object() //创建了一个对象,针对object也有new这个过程
针对object也有new这个过程
针对object也有new这个过程,这里怎么理解呢?在我之前写的两篇文章里都有介绍过,这里我再解释一下,如果没看过我之前两篇文章的朋友,可以访问JS批量创建对象的方案与构造函数、JS中对象的原型与函数的原型 进行阅读。
此处new操作符经历的过程
- 现在内存中创建一个对象 let moni = {}
- this指向这个对象,也就是this = moni
- 将函数的显示原型prototype赋值给前面创建出来的对象的隐式原型,这里也就是obj2.__ proto __ = Object.prototype
- 如果构造函数没有对象,则返回空值。反之返回创建出来的新对象(moni)。这里也就是return this。
验证一下
console.log(obj2.__proto__ === Object.prototype)
并且大家要知道Object是所有对象的父类,(它是最顶层的原型)
研究一下Object.prototype里有什么
let obj1 = new Object()
console.log(Object.getOwnPropertyDescriptors(Object.prototype));
打印出来我们会发现,有非常多的值。
{
constructor: {
value: [Function: Object],
writable: true,
enumerable: false,
configurable: true
},
__defineGetter__: {
value: [Function: __defineGetter__],
writable: true,
enumerable: false,
configurable: true
},
__defineSetter__: {
value: [Function: __defineSetter__],
writable: true,
enumerable: false,
configurable: true
},
hasOwnProperty: {
value: [Function: hasOwnProperty],
writable: true,
enumerable: false,
configurable: true
},
__lookupGetter__: {
value: [Function: __lookupGetter__],
writable: true,
enumerable: false,
configurable: true
},
__lookupSetter__: {
value: [Function: __lookupSetter__],
writable: true,
enumerable: false,
configurable: true
},
isPrototypeOf: {
value: [Function: isPrototypeOf],
writable: true,
enumerable: false,
configurable: true
},
propertyIsEnumerable: {
value: [Function: propertyIsEnumerable],
writable: true,
enumerable: false,
configurable: true
},
toString: {
value: [Function: toString],
writable: true,
enumerable: false,
configurable: true
},
valueOf: {
value: [Function: valueOf],
writable: true,
enumerable: false,
configurable: true
},
['__proto__']: {
get: [Function: get __proto__],
set: [Function: set __proto__],
enumerable: false,
configurable: true
},
toLocaleString: {
value: [Function: toLocaleString],
writable: true,
enumerable: false,
configurable: true
}
}
重点关注一下,打印的这么多值里也有constructor
,在我的上一篇文章已经分析过了,这里constructor
指向的就是构造函数本身,此处也就是Object。
来自本人掘金内容 https://juejin.cn/post/7111332278805987364/