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。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值