在前端开发的工作中,JavaScript的原型链到处可见,它主要是为了解决继承的问题,因为js本身就是一门面向对象的语言,而继承是面向对象编程的三要素之一,那么如何来理解并实现js中的继承呢。
构造函数
JavaScript中,通过构造函数来实现对象的继承,最明显的就是,构建一个对象
let obj = new Object();
Object本身就是一个构造函数,通过模板化的形式,来生成一个个对象实例,现在我们新建一个构造函数
function Cat就是构造函数,cat就是它生产出来的实例,说了这些,跟原型有什么关系呢?
function Cat(){
this.age = 3;
}
let cat = new Cat();
console.log(cat.age) // 3
Cat就是构造函数,cat就是它生产出来的实例,说了这些,跟原型有什么关系呢?
每个函数都有一个prototype,它本身是一个对象,指向函数的原型,如图为打印结果
可以看到Cat.prototype的值,包含了构造函数 constructor 和 __proto__。
__proto__是什么
每个对象实例都有 __proto__,指向实例对象的原型,这个由运行环境来提供
function Cat() {
this.color = 'orange'
}
var cat = new Cat()
console.log(cat.__proto__)
console.log(Cat.prototype === cat.__proto__) // true
具体可以参考下图:
细心的你应该已经发现了,上图的右边有一条线还没有结束,这个是指什么呢?
继承
我们先写一段代码
function Cat(){
this.age = 3;
}
Cat.prototype.name = 'mi';
let cat = new Cat();
cat; // Cat {age: 3}
cat.name // "mi"
console.log(cat.hasOwnProperty('age')) // true
console.log(cat.hasOwnProperty('name')) // false
可以看到,虽然cat实例有name属性并且可以访问,但是name属性并不属于它本身,而是继承自 Cat, cat实例本身没有这个属性值,可以通过原型链来逐级访问,这就是所谓的继承。当访问对象的某一属性无法访问到,就会逐级去访问原型链(通过 __proto__,如: Cat.prototype.__ptoto__ , cat.__proto__.__proto__ ),来获取到这个值,直到原型链返回null,为什么会返回null呢?
对象的构造函数为 Object,那我们来看下它的原型是什么?
Object.prototype.__proto__ // null
所以 Object.prototype就是传说中的最高级了,位于原型链的最顶端。下面奉上完整的图片: