继上一次文章,相比较闭包和作用域,原型和原型链的理解没有那么的抽象晦涩,但其中依然有一些坑值得注意,这次就来记录一下自己的踩坑过程,适合初学者更好的理解原型和原型链。
一.原型
1.关于实例化
废话不多说,直接贴代码,也请读者思考一下输出结果。
function Car () {
}
var car = new Car()
Car.prototype.name = 'BMW'
console.log(car.prototype)
其实这里输出的是undefined。prototype只有函数对象Car有,即使被car实例化了 ,也只是继承prototype里的属性。
2.关于原型属性的操作
原型的属性可以进行增删改查的操作,但是不同的修改方式可能一不小心让你掉进陷阱。
Person.prototype.name = '张三'
function Person () {
}
var person = new Person ()
Person.prototype.name = '李四' // 修改prototype的属性
console.log(person.name) // 李四
到这里,都是正常的操作,理所应当,合情合理。那如果接下来这样修改呢?
Person.prototype = {
name: '李四'
}
console.log(person.name) // ???
眉头一皱,发现事情并不简单,这里输出的其实还是李四。这是为什么呢?是不是哪里出了问题?但仔细想想也就能明白这里两者的根本区别,第二次是把原型重新赋值,这个对象在新的一个地址里 ,在这里改变name不影响protorype之前继承的地址里的name属性
二.原型链
原型的相互嵌套,一层层的链式连接叫做原型链。原型链最关键的两个属性prototype和__proto__以及他们里面所自带的方法,你真的弄清楚了吗?
1.关于__proto__里的方法(包装类)
var num = 123
num.toString()
大家是否想过为什么Number类型会有一个toString()的方法的可以调用?这里涉及到包装类的知识。
var num = 123
num.toString() // ----> new Number(num).toString()
num当成Number对象进行实例化,
Number.prototype.__proto__指向的就是Object.prototype。num自然而然找到Object.prototype里的toString()方法。现学现用!我们就可以进行方法重写
Object.prototype.toString = function() {
return 'hhhh'
}
function Person() {
}
var person = new Person()
console.log(person.toString()) // 'hhhh'
2.对象的最终指向
网易有一道面试题,所有对象最终都会继承自Object.prototype吗?
var obj = Object.create(null)
var obj2 = Object.create(obj)
这里就不难发现obj2是个空的对象,
obj2.__proto__里面什么都没有.所以当由null生成的对象最终是不会继承Object.prototype。
三.结语
本文没有写过多的基础原理,而是针对有一定基础了解的人在面试、在工作中防坑指南。希望此文对大家有所借鉴哈,有问题的欢迎评论区指出和讨论。