文章目录
继承篇
原型链继承
当我访问一个对象实例的属性时候,这个就会在实例的本身找是否存在这个属性,如果没有则访问[__proto__]
或者prototype
所以,如果我们需要实现继承,可以通过修改构造函数的原型来实现,这样每一个实例都可以得到父类
的属性和方法。
我们直接代码来看下如何实现吧!
var Father = function(age) {
this.name = 'father'
this.age = age
}
var Son = function (){
}
Son.prototype = new Father()
Son.prototype.returnFather= function(){
console.log(this.name,this.age)
}
var son1 = new Son('53')
son1.returnFather()
输出
father undefined
这里undefined
是因为father实例
没有一个构造函数constructor
的指针,所以new的时候没有指向到father
的构造函数
我们通过代码来验证下原型的关系
var Father = function(age) {
this.name = 'father'
this.age = age
}
var Son = function (){
}
var _f = new Father()
Son.prototype = _f
Son.prototype.returnFather= function(){
console.log(this.name,this.age)
}
var son1 = new Son('53')
son1.returnFather()
console.log(son1.__proto__== _f) // true
console.log(Father.prototype== _f.__proto__)// true
借用构造函数继承
我们前面了解new
的过程就是绑定一个对象作用域并且指向构造函数返回对象,就可以获取到构造函数里面的属性和方法。
我们同样可以将父类的构造函数进行手动的绑定作用域,并且执行。这样在new
子类的时候就可以类似同时在new
父类的构造函数一样。
var Father = function(age) {
this.name = 'father'
this.age = age
}
var Son = function (age){
Father.call(this,age)
}
var son1 = new Son('53')
console.log(son1.age) // 53
var son2 = new Son('32')
console.log(son2.age) // 32
组合式继承
结合构造函数和原型,我们需要将共享的方法和属性通过原型继承,而除此之外,我们需要对构造函数调用父类的构造函数继承实例的属性和方法。
var Father = function(age) {
this.name = 'father'
this.age = age
}
var Son = function (age){
Father.call(this,age)
}
Son.prototype = new Father()
Son.prototype.constructor = Son
Son.prototype.returnName = function() {
return this.name
}
var son2 = new Son('32')
console.log(son2.age,son2.returnName())
Son.prototype.constructor = Son
重要的是这一步,因为你修改了原本Son
的prototype
,因为new
调用的构造函数constructor
是保存到原型上的,所以你需要手动的添加到原型上。
还有一个需要注意,因为这种方法的函数需要自己另外添加,因为你如果写进Father
的构造函数,这样每个实例都会存在一份这个函数的变量。
原型式继承
var creatObject = function (o) {
var obj = function(){}
obj.prototype = o
return new o()
}
这个看起来非常熟悉,其实就是我们object.create
的方法
创造的实例的prototype
就是父类,这个缺点就导致了父类所有属性和方法都是共用的。
我们可以将这些额外需要添加的封装到一个方法里,这样就是寄生式继承
寄生式继承(工厂模式)
function create (father) {
var clone = Object.create(father)
clone.sayName = function(){console.log(this.name)}
return clone
}
寄生式组合继承
我们组合继承有一个问题就是构造函数放的是属性,而父类原型放的是方法,通过构造函数继承属性,通过原型链继承方法。
var Father = function(age) {
this.name = 'father'
this.age = age
}
var Son = function (age){
Father.call(this,age)
}
function create(son,father){
var prototype = Object.create(father.prototype)
son.prototype = prototype
son.prototype.constructor = son
}
var obj = create(Son,Father)
// obj的prototype指向的是父类的prototype,所以只需要往父类prototype的添加方法即可
ES6进化篇
ES6的class
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
constructor
构造函数,存放属性- 其他直接设置为原型的方法,不用添加
function
等价于ES5的写法
var Point = function (x,y){
this.x = x;
this.y = y;
}
Point.prototype.toString() {
return '(' + this.x + ', ' + this.y + ')';
}
- 静态方法/属性
class Point {
}
Point.test = function(){console.log(1)}
Point.prop = 1;
var p = new Point()
p.test()// 报错
p.prop //undefined
- 除了在构造函数添加实例属性,我们也可以尝试使用其他方法
class Point {
constructor() {
this._count = 0;
}
get Value(){
return this._count;
}
}
var p = new Point()
console.log(p.value)// 0
ES6的继承
- 规则使用
extends
进行继承 - 子类构造函数开头一定需要携带
super(); // 调用父类的constructor()
class Point { /* ... */ }
class ColorPoint extends Point {
constructor() {
super()
}
}
let cp = new ColorPoint();
判断父子类关系
Object.getPrototypeOf(ColorPoint) === Point //true
class中的prototype和__proto__
(1)子类的__proto__
属性,表示构造函数的继承,总是指向父类。
(2)子类prototype
属性的__proto__
属性,表示方法的继承,总是指向父类的prototype
属性。