js的继承

继承的原理就是原型链,继承的本质就是原型链,如果没有原型链在JS中是很难实现继承的。

ES5中的:

所有的引用类型都可以自定义添加属性。

所有的引用类型都有自己的隐式原型(__proto__)。

函数都有自己的显式原型(prototype)。

所有的引用类型的隐式原型都指向对应构造函数的显示原型 __proto__ -> prototype原型。

使用引用类型的某个自定义属性时,如果没有这个属性,会去该引用类型的proto(也就是对应构造函数的prototype)中去找。

继承的方式:

一、构造函数实现继承

//将父级的构造函数this指到子构造函数的实例上去,在子类中就能看到父类的属性和方法。

function  father() {
    this.name = 'father'
}
function  son() {
    father.call(this) 
// 把父级father构造函数在子类的构造函数里面执行,并且同时修改了父级构造函数的this指向,
//也就是指向了son这个类实例化的对象的引用。
//因为this指向导致父类执行的时候属性都会挂在到son这个类的实例上去。
    this.type = 'son'
}
console.log(new  son)

 缺点:

father除了构造函数里面的内容,它原型链上的东西并未继承,只是实现了部分继承。

//将父级的构造函数this指到子构造函数的实例上去,在子类中就能看到父类的属性和方法。

function  father() {
    this.name = 'father'
}
father.prototype.say = function() {} // 不能被son继承
function  son() {
    father.call(this) 
// 把父级father构造函数在子类的构造函数里面执行,并且同时修改了父级构造函数的this指向,
//也就是指向了son这个类实例化的对象的引用。
//因为this指向导致父类执行的时候属性都会挂在到son这个类的实例上去。
    this.type = 'son'
}
console.log(new  son)

二、原型链的继承

////

// 父类
    function Father(x, color) {
      this.x = x
//私有属性
      this.color = function () {
        return "red"
      }
    }
//公有属性
    Father.prototype.getx = function () {
      console.log("getx===>", this.x);
    }

    // 子类
    function Son(y) {
      this.y = y
    }
    Son.prototype.gety = function () {
      console.log("gety===>", this.y);
    }

    // 子类的prototype指向父类的实例对象
    Son.prototype = new Father(111)
    // 让子类的prototype的constructor重新指向son
    Son.prototype.constructor = Son

    let son1 = new Son(222)
    console.log(son1);

三、组合继承

// 父类
    function Father(x, color) {
      this.x = x
      this.color = function () {
        return "red"
      }
    }
    Father.prototype.getx = function () {
      console.log("getx===>", this.x);
    }

    // 子类通过call继承
    function Son(y) {
      this.y = y
      // 修改this指向,通过call继承获取父类属性
      Father.call(this, 111)
    }
    Son.prototype.gety = function () {
      console.log("gety===>", this.y);
    }

    // 子类的prototype指向父类的实例对象
    Son.prototype = new Father()
    // 让子类的prototype的constructor重新指向son
    Son.prototype.constructor = Son

    let son1 = new Son(222)
    console.log(son1);

 四、寄生组合继承

// 父类
    function Father(x, color) {
      this.x = x
      this.color = function () {
        return "red"
      }
    }
    Father.prototype.getx = function () {
      console.log("getx===>", this.x);
    }

    // 子类通过call继承
    function Son(y) {
      this.y = y
      // 修改this指向,通过call继承获取父类属性
      Father.call(this, 111)
    }
    Son.prototype.gety = function () {
      console.log("gety===>", this.y);
    }

    // 创建一个对象,这个对象的constructor指向构造函数的原型Son.prototype
    // ,然后他的--proto--指向父类的显示原型prototype
    Son.prototype = Object.create(Father.prototype)
    // 让子类的prototype的constructor重新指向son
    Son.prototype.constructor = Son

    let son1 = new Son(222)
    console.log(son1);

五、原型链是通过prototype原型和__proto__属性,来完成原型链的向上查找的过程的

原型对象,怎么区分是哪个构造函数引用的

function Person1(name1) {
  this.name1 = name1
}

function Person(name) {
  this.name = name
}
let p1 = new Person()
console.log(Person.prototype.constructor === Person) // true

是通过constructor(构造器),原型对象中会有一个构造器,这个构造器默认声明的那个函数,构造函数有prototype也就是原型对象,这个原型对象里面有一个constructor属性,这个属性指向了一个函数,这个函数就是构造函数,如果两者相等证明是有引用关系的否则没有关系

六、实例对象和原型对象之间的关系

function Person(name) {
  this.name = name
}
let p1 = new Person()
console.log(p1.__proto__ === Person.prototype) // p1实例对象的__proto__引用的Person构造函数上的原型对象

七、原型对象和构造函数的关系

function Person(name) {
  this.name = name
}
let p1 = new Person()
console.log(Person.prototype.constructor === Person) // true

构造函数的原型对象通过constructor和构造函数保持关联,也就是构造函数下的constructor属性指向构造函数他们两者相等。

八、判断一个实例对象和构造函数在不在同一个链条中

function Person1(name1) {
  this.name1 = name1
}

function Person(name) {
  this.name = name
}
let p1 = new Person()
console.log(p1 instanceof Person) // true
console.log(p1 instanceof Object)  // true

p1实例对象在Person构造函数上返回true,p1实例对象在Object构造函数上也返回true,那么就证明了实例对象和构造函数在同一个原型链中。

console.log(p1.__proto__ === Person.prototype) // true
console.log(Person.prototype.__proto__ === Object.prototype) // true

只要是在原型链上的构造函数都会被instanceof看做是一个p1实例对象上的函数。

ES6中的:

九、class的继承,通过extends关键字就可以实现了

es5 的继承是通过原型或者是构造函数机制来实现,es6 用过 class 关键字定义类,里面有构造方法,类之间通过 extends 关键字实现,子类必须在 constructor 方法中调用 super 方法

class Father{ // 父类
}
class Son extends Father { // 子类继承父类
} 

什么是 Class,Class 的作用

ES6 的 Class 可以看作只是一个 ES5 生成实例对象的构造函数的语法糖。

定义了一个类的概念,让对象原型写法更加清晰,对象实例化更像是一种面向对象编程。

什么是 extends,extends 的作用

extends 是ES6 引入的关键字,其本质仍然是构造函数+原型链的组合式继承。Class 类可以通过 extends 实现继承。

Class 和 ES5 构造函数的不同点

ES6 的 class 类必须用 new 命令操作,而 ES5 的构造函数不用 new 也可以执行

ES6 的class 类不存在变量提升,必须先定义class 之后才能实例化,不像ES5 中可以将构造函数写在实例化之后。

ES5 的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到 this 上面。ES6 的继承机制完全不同,实质是先将父类实例对象的属性和方法,加到this 上面(所以必须先调用super 方法),然后再用子类的构造函数修改this。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值