原型和原型链在 JavaScript 里是一个非常重要的概念和应用。在前端的面试中一般情况下也是必考题目
那么怎么才能非常准确的理解原型和原型链呢?
原型
想要解释原型,得先知道两个属性
首先,每一个函数都有一个 prototype
属性,称作“原型”,属性值的数据类型是 Object
当解释原型时,通常指的是一个引用类型
的变量的原型
引用类型有一个 __proto__
的属性,称作隐式原型
,属性值的数据类型是 Object
const arr = [1, 2, 3, 4]
console.log(arr.__proto__)
引用类型的 __proto__
属性指向的是其构造函数的 prototype
属性
这个例子可以看出,arr 的构造函数是 Array()
一个数组可以直接声明,也可以这样声明:
conat arr = new Array()
所以
arr.__proto__ === Array.prototype // true
原型链
const obj = {
test: 'fine'
}
当访问一个 对象
类型变量的属性时,会首先在这个对象上寻找
console.log(obj.test) // fine
如果对象上没有这个属性,则会到他的隐式原型 __proto__
上(也就是它的构造函数的 prototype
)找
console.log(obj.hasOwnProperty('test')) // true
如果还没有找到,就会一直查找其原型的原型,最后会查找到 null 上
这种一层层向上查找的链条,就是原型链
原型链编程
有时候我们会给某一种数据类型的原型上添加一些属性或者方法,来进行一些操作,例如:
String.prototype.repeat = function (count) {
let str = ''
for (let i = 0; i < count; i += 1) {
str += this
}
return str
}
console.log('hi'.repeat(3))
有时候我们会自己定义构造函数
例如构造函数 Cat
构造猫,javis
是我家养的一只猫,是 Cat
构造出来的,所以要 new 一个 Cat
对象
Cat 构造函数可以传入 name
和 walk
, javis
被声明以后传入了一个 gender 属性
所以一下控制台输出分别演示了 javis
这个对象的属性、原型和原型链
function Cat (name) {
this.name = name
this.walk = 'catwalk'
}
const javis = new Cat('javis')
javis.gender = 'male'
console.log(javis.gender) // male
console.log(javis.name) // javis
console.log(javis.walk) // catwalk
console.log(javis.hasOwnProperty('meow') // false
console.log(javis.meow) // undefined
总结
一个对象实体的隐式原型指向它的构造函数的显式原型
构造函数的隐式原型指向 Object 的显式原型
Object 的隐式原型指向 null
这就构成了原型链
可以在原型链上编程完成一些工作