继承的原理就是原型链,继承的本质就是原型链,如果没有原型链在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。

628

被折叠的 条评论
为什么被折叠?



