前言
🙋♂️ 知其然,更知其所以然,举一反三,融会贯通
javascript中的原型和原型链可以说是谈论最多的一个知识点了,特别作为面试题,可以很轻易了解一个人的对js的认知水平,我觉得主要有两方面,一方面原型是js语言的核心(偏底层),另一方面在实际开发场景中用到的并不是特别多(除了某些库),很容易针对面试者,答不出来理所应当的可能会被减分,让自己的竞争者处于劣势。
温故而知新,今天再来梳理下有关原型方面的知识点,慢慢养成写文章的好习惯😃
白话
我对原型和原型链概念的简单理解:
- 每个构造函数都有对应的prototype
(显式的原型)和__proto__(隐式的原型)属性
-
prototype指向一个对象,它有一个constructor属性,constructor属性默认指向构造函数本身(是可以被改写的)
-
__proto__属性指向它的构造函数的prototype属性
- 一切对象都有一个隐式的原型属性__proto__
-
__proto__指向它的构造函数prototype属性,js内部就是通过此属性来实现继承
-
普通的对象没有prototype属性,prototype是函数特有的属性
简单从字面理解起来是不是很绕口😆,也不知道是否理解完全正确。还是来看看具体的实例吧~
原型
__proto__属性
首先来看两个例子:
const obj = {}
obj.__proto__.title = 'hello world'
console.log(obj.title)
输出的结果是:hello world
const obj = { title: 'hi world'}
obj.__proto__.title = 'hello world'
console.log(obj.title)
输出的结果是:hi world
我们对上面的结果做一下分析:
第一个例子:定义的obj对象上面没有title属性,我们通过obj.__proto__设置属性后,通过obj.title就可以访问到了,上面有提到过,每个对象都有一个_proto__属性(指向它的原型),当我们通过对象访问属性的时候,首先会从对象中读取,如果没有属性,则会从对象的__proto__属性中读取,这个操作是js内部帮我们做的。
第二个例子:很明显,对象中存在title属性,就算原型里有title,也不会去读取了,优先读取自身的属性
从现实中继承的角度可以这样理解:我想买个手机,但我身上没钱(money属性),那么我就可以问我爸要money,我爸把钱花了,也没钱,我就可以在继续问我爷爷要money, 如果爷爷有钱,那么我就可以达成心愿,如果爷爷也没钱,那么我的计划就泡汤啦~
prototype属性
prototype属性就是上面所提到的原型对象
还是来看看例子
function Person(userName, sex) {
this.userName = userName
this.sex = sex
}
person.prototype.isChina = true
Person.prototype.speek = () => {
console.log('speek')
}
const person1 = new Person('tony', '男')
const person2 = new Person('mali', '女' )
console.log(person1.userName) // tony
console.log(person1.isChina) // true
console.log(person2.userName) // mali
console.log(person2.isChina) // true
person1.__proto__.isChina = false
console.log(person1.isChina) // false
console.log(person2.isChina) // false
上面我们定义了一个Person构造函数,给它添加了两个原型属性,然后构造出两个对象person1和person2,此时person1和peroson2的__proto__都会指向Person的prototype属性,当我们读取isChina属性的时候,是能返回值的,最后我们通过person1.__proto__.isChina对值进行修改,结果person1和person2读取的isChina都是返回相同的值,再一次印证他们的原型指向的是同一个对象
person1.__proto__ === Person.prototype
person2.__proto__ === Person.prototype
原型链
原型链就是对象不断通过__proto__来实现继承(prototype对象),形成的一个链条,从底层不断的往上层寻找, 那么就会有一个问题,难道没有尽头吗? 原型链的终点是什么!
原型链是有尽头的,js中所有其他对象都是继承Object对象,原型链的顶端是null
Object.prototype.__proto__ === null
JS中Object和Function构造函数是比较特殊的,Function是自身自己构造的,而Object也是Function构造的
Function.__proto__ === Object.prototype // false
Funciton.__proto__ === Function.prototype // true
Object.__proto__ === Function.prototype // true