class Person { constructor(x,y) { this.x = x this.y = y } add() { return this.x + this.y } } let person = new Person(1,2) console.log(person.add()) // 3
经过类Person
的构造函数实例化了一个对象person
,person
继承了类的add
方法
ES6以前是没有类的概念,因此要实现上面的操做,须要function
出马函数
function Person(x, y) { // 首字母大写表示它是个类函数 this.x = x this.y = y this.add = function() { return this.x + this.y } } let person = new Person(1,2) console.log(person.add()) // 3
这样虽然实现了,可是明显有缺点,上面ES6类的构造函数仅初始化了x,y
,默认继承了add
方法,而function
方式的须要初始化全部,因此须要优化优化
function Person(x, y) { this.x = x this.y = y } Person.prototype.add = function() { return this.x + this.y } let person = new Person(1,2) console.log(person.add()) // 3
很明显,经过Person.prototype
实现了class
中this
的做用,这就叫实例原型(实例对象自己就是从类实例化而来,可不就是实例原型)
既然与ES6 class
挂上了钩,这时还缺乏一个constructor
,巧了,实例原型刚好有一个属性constructor
指向构造函数自己
并且为了造成一个闭环,实例对象也有一个属性__proto__
指向实例原型
this
由于全部对象都继承于
Object
,因此会有下面的一部分
class Father{ constructor(name,age) { this.name = name this.age = age } // 此处的方式实际上是挂载在prototype属性上的,反推上面的ES5 语法 sayName() { console.log(this.name + this.age) } } class Child extends Father{ constructor(name, age, job) { super(name,age) // 必须调用super方法,而且必定要在使用this以前调用,至关于Father.prototype.constructor.call() this.job = job } sayJob() { console.log(this.job) } // 覆盖父类的方法 sayName() { console.log('hello world') // 调用父类的属性,输出:hello world } } let kid = new Child('nike','20','teacher') kid.sayJob() // teacher kid.sayName() // hello world
其中的关键是super
,super
做为一个方法在调用父类的构造函数,同时也能够做为一个对象,指向父类的prototype
对象,而上面的调用父类属性会出现undefined
,由于name
并无挂载在父类的prototype
上,从新改造一下spa
class Father{ constructor(name,age) { Father.prototype.name = name this.age = age } }
由于sayName
方法是挂载在prototype
属性上的,因此能够直接super.sayName()
调用,并且调用方法执行的上下文this
是指向子类的prototype
class Father{ constructor(name,age) { this.name = name this.age = age this.job = 'Hello world' } sayJob() { console.log(this.job) } } class Child extends Father{ constructor(name, age, job) { super(name,age) // 必须调用super方法,而且必定要在使用this以前调用 this.job = job } sayJob() { super.sayJob() // teacher } } let kid = new Child('nike','20','teacher') kid.sayJob() // teacher
从上面的分析可知,xxx.prototype
做为实例原型,它拥有跟实例对象同样的属性和方法,因此只须要把父类的实例对象赋值给子类的prototype
属性,那么不就继承了code
function Father(name) { this.name = name } function Child(age) { this.age = age } Child.prototype = new Father('nike') // 将父类的实例对象赋值给Child的prototype let kid = new Child(20) // 实例子类对象 console.log(kid.name) // nike console.log(kid.age) // 20
由于ES5的类
是个函数,因此借助函数的特性能够实现另一种继承对象
function Father(name) { this.name = name } function Child(age) { Father.call(this, 'nike') this.age = age } let kid = new Child(20) console.log(kid.name) // nike
这两个就够了,其余方式都是多此一举继承
person instanceof Person // true person instanceof Object // true Person.prototype.isPrototypeOf(person) // true Object.prototype.isPrototypeOf(person) // true