JavaScript 基础——4.JavaScript 面向对象 (2)

一、JavaScript 原型

  • 原型:[[Prototype]]
  • ECMA-262 把 原型链 定义为 ECMAScript 的主要继承方式
  • 继承关系的判断:
    • sourceObject instanceof TargetObject
    • TargetObject.isInstanceOf(sourceObject)
  • 原型设置:Object.setPrototypeOf(target, source)
  • 原型获取:Object.getPrototypeOf(target)
  • 原型判定:target.isPrototypeOf(source)
  • 所有引用类型的对象,其原型链顶端都是:Object.prototype

二、JavaScript 继承

JavaScript 中的继承基本上都是基于原型的,主要有以下继承方式:

  • 原型链继承
  • 盗用构造函数继承
  • 组合式继承
  • 原型继承
  • 寄生式继承
  • 寄生组合式继承

1. 原型链继承

原型链继承是通过直接修改子构造函数的原型来实现的,示例代码如下:

function Super() {}
function Sub() {}

Sub.prototype = new Super();
const sub - new Sub();
console.log(sub instanceof Super); // true

这样的缺点有:

  • 父类的实例属性成了子类的原型属性,会被子类所有实例共享
    • 当实例属性是原始值时,是没有问题的
    • 当实例属性是引用值时,会有巨大的问题:在一个地方发生了改动,会影响到所有的地方
  • 必须在构造函数中定义方法,函数不能重用

2. 盗用构造函数继承

盗用构造函数继承,是通过在子类型中调用父类型的构造函数来实现的。

function Super(name) {
	this.name = name
}
function Sub() {
	Super.call(this, "Nico");
}

const sub = new Sub();
console.log(sub instanceof Super); // false

缺点:

  • 必须在构造函数中定义方法,函数不能重用
  • 子类不能访问父类原型上定义的方法

3. 组合继承

又名:伪经典继承。
组合了原型链 (继承方法) 和盗用构造函数 (继承属性) 继承。

function SuperType(name){
	this.name = name;
	this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function() {
	console.log(this.name);
};
function SubType(name, age){ // 继承属性
	SuperType.call(this, name); this.age = age;
}
// 继承方法
SubType.prototype = new SuperType();
// 子类自己的方法
SubType.prototype.sayAge = function() {
	console.log(this.age);
};
  • 优点:
    • 保留了 instanceof 和 isPrototypeOf()识别合成对象的能力
  • 缺点:
    • 缺点:调用了两次 Super 的构造函数

4. 原型式继承

一种不涉及严格意义上的构造函数的继承方法。

  • 适用场景:有一个对象,想在它的基础上再创建一个新对象。
  • ES5 支持类似这样的创建方式:const target = Object.create(source)
    • Object.create 将原型式继承的概念规范化了

5. 寄生式继承

  • 与原型式继承比较接近
  • 思路类似于寄生构造函数和工厂模式:创建一个实现继承的函数,以某种 方式增强对象,然后返回这个对象。
  • 适用场景:主要关注对象,而不在乎类型和构造函数
  • 缺点:
    • 通过寄生式继承给对象添加函数会导致函数难以重用,与盗用构造函数继承模式类似

6. 寄生式组合继承

通过盗用构造函数继承属性,但使用混合式原型链继承方法。
基本模式:

function inheritPrototype(subType, superType) {
	let prototype = object(superType.prototype); // 创建对象
	prototype.constructor = subType; // 增强对象
	subType.prototype = prototype; // 赋值对象
}

这种继承方式可以算是引用类型继承的最佳模式。

三、JavaScript 中的类

  • JavaScript 中的 class 和 extends 仅仅只是一个语法糖
    • 本质仍然是基于原型链的继承
  • 定义方式:
    • 类声明 (类似函数声明)
    • 类表达式 (类似函数表达式)
  • 注意
    • 类产生的作用域实质是一个块级作用域
    • 类中的 非 static 方法 的 this 始终指向类的实例
    • 类的实例对象上不存在 static 方法
    • 只能通过 ClassName.staticMethod() 的方式调用静态方法
    • Class 最终仍继承自 Object
  • 类中可以有的内容:
    • constructor 构造函数
    • 静态方法
    • 实例方法
    • getter 属性方法
    • setter 属性方法
    • 实例属性
  • 类的继承
    • 模式:class SubType extends SuperType {}
    • SuperType 的限制:
      • 必须有 [[Construct]] 和 [[Prototype]]
    • 在 SubType 中使用 super 的限制:
      • 在类构造函数中,不能在调用 super()之前引用 this
      • 如果在派生类中显式定义了构造函数:
        • 要么必须在其中调用 super()
        • 要么必须在其中返回一个对象
      • 只能在派生类 构造函数静态方法 中使用,实例方法中不能使用
      • 不能单独引用,要么用它调用构造函数,要么用它引用静态方法
      • 调用 super() 时,会调用父类构造函数,并将返回的实例赋值给 this
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值