JS高级程序设计之class继承重点详解


Posted in Javascript onJuly 07, 2022

引言

前文已提过:在 class 出现之前,JavaScript 实现继承是件麻烦事,构造函数继承有加上原型上的函数不能复用的问题;原型链继承又存在引用值属性的修改不独立的问题;组合继承又存在两次调用构造函数的问题,寄生组合继承,写起来又太麻烦了,总之,在 class 出现前,JavaScipt 实现继承真是件麻烦事儿。

然而,class 的出现真的改变这一现状了吗?

不如往下看。

写法

与函数类型相似,定义类也有两种主要方式:类声明和类表达式。

// 类声明 class Person {}

// 类表达式 const Animal = class {};

不过,与函数定义不同的是,虽然函数声明可以提升,但类定义不能。

与函数构造函数一样,多数编程风格都建议类名的首字母要大写,以区别于通过它创建的实例。

类可以包含:

  • 构造函数方法
  • 实例方法
  • 获取函数
  • 设置函数
  • 静态类方法

这些项都是可选的

constructor

class Person { 
    constructor(name) {
        this.name = name
        console.log('person ctor');
    }
}
let p1 = new Person("p1")

constructor 会告诉解释器 在使用 new 操作符创建类的新实例时,应该调用这个函数。

等同于

function Person(name){
    this.name = name
    console.log('person ctor')
}
let p1 = new Person("p1")

类构造函数与构造函数的主要区别是,这样写会报错:

class Animal {}
let a = Animal(); // TypeError: class constructor Animal cannot be invoked without 'new'

所以,new 操作符是强制要写的;

使用 new 时,原理与 new 一个对象也是一样的,因为太重要了,再强调一遍:

(1) 在内存中创建一个新对象。

(2) 这个新对象内部的[[Prototype]]指针被赋值为构造函数的 prototype 属性。

(3) 构造函数内部的 this 被赋值为这个新对象(即 this 指向新对象)。

(4) 执行构造函数内部的代码(给新对象添加属性)。

(5) 如果构造函数返回非空对象,则返回该对象;否则,返回刚创建的新对象。

特性

从各方面来看,ECMAScript 类就是一种特殊函数。

我们可以用 typeof 打印试试:

class Person {} 
console.log(typeof Person); // function

也可以用 instanceof 检查它的原型链

class Person {} 
let p = new Person()
console.log(p instanceof Person); // true

通过 class 构造的每个实例都对应一个唯一的成员对象,这意味着所有成员都不会在原型上共享;

class Person {
 constructor() {
 this.name = new String('Jack');
 this.sayName = () => console.log(this.name);
 }
}
let p1 = new Person();
let p2 = new Person();
console.log(p1.name === p2.name) // false
console.log(p1.sayName === p2.sayName) // false

如果想要共享,就改写成方法,写在 constructor 外面:

class Person {
 constructor() {
 this.name = new String('Jack');
 }
 sayName(){
      console.log(this.name);
 }
}
let p1 = new Person();
let p2 = new Person();
console.log(p1.sayName === p2.sayName) // true

我们可以在方法前面加 static 关键字,实现:静态类成员。我们不能在类的实例上调用静态方法,只能通过类本身调用。不做赘述。

继承

ECMAScript 6 新增特性中最出色的一个就是原生支持了类继承机制。虽然类继承使用的是新语法,但背后依旧使用的是原型链

让我们再回顾构造函数继承和原型链继承 2 个经典的问题:

① 构造函数继承的问题:构造函数外在原型上定义方法,不能重用

function SuperType(){}
SuperType.prototype.sayName = ()=>{console.log("bob")}
function SubType(){
    SuperType.call(this) // 构造函数继承
}
let p1 = new SubType()
console.log(p1.sayName()) // Uncaught TypeError: p1.sayName is not a function

而原型链继承可以解决这一点:

function SuperType(){}
SuperType.prototype.sayName = ()=>{console.log("bob")}
function SubType(){}
SubType.prototype = new SuperType()  // 原型链继承
let p1 = new SubType()
console.log(p1.sayName()) // bob

② 原型链继承的问题:原型中包含的引用值会在所有实例间共享。

function SuperType(){
    this.name = ["bob","tom"];
}
function SubType(){}
SubType.prototype = new SuperType()  // 原型链继承
let p1 = new SubType()
p1.name.push("jerry")
let p2 = new SubType()
console.log(p2.name) //  ['bob', 'tom', 'jerry']

而构造函数继承可以解决这一点:

function SuperType(){
    this.name = ["bob","tom"];
}
function SubType(){
    SuperType.call(this) // 构造函数继承
}
let p1 = new SubType()
p1.name.push("jerry")
let p2 = new SubType()
console.log(p2.name) //  ['bob', 'tom']

class 继承有这两个问题吗??

代码一试便知:

class SuperType{}
SuperType.prototype.sayName = ()=>{console.log("bob")}
class SubType extends SuperType{
}
let p1 = new SubType()
p1.sayName() // bob

问题①,没有问题,在构造函数外写的原型继承,公共方法还是能访问的!!

class SuperType{
    constructor(){
        this.name=["bob","tom"]
    }
}
class SubType extends SuperType{
}
let p1 = new SubType()
let p2 = new SubType()
p1.name.push("Jerry")
console.log(p2.name) //  ['bob', 'tom']

问题②,没有问题,在 constructor 的引用值属性,修改不会产生干涉!!

class 继承完美的解决了构造函数继承的问题,和原型链继承的问题,写起来也没有组合继承、寄生继承那么麻烦,如果非得用 JS 模拟面向对象编程,class 必不可少!!

题外话

其实写 Class C 和 C.prototype 一起写是很危险的:明明都在操作面向对象的类了,还要操作原型链。类操作和原型操作是两种不同的设计思路,有兴趣可见本瓜一年前的一篇文章:“类”设计模式和“原型”设计模式——“复制”和“委托”的差异

以上就是JS高级程序设计之class继承重点详解的详细内容,更多关于JS高级程序设计class继承的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
JavaScript 程序编码规范
Nov 23 Javascript
js去除空格的12种实用方法
Nov 08 Javascript
一段非常简单的js判断浏览器的内核
Aug 17 Javascript
jQuery使用prepend()方法在元素前添加内容用法实例
Mar 26 Javascript
js简单实现点击左右运动的方法
Apr 10 Javascript
学习Javascript面向对象编程之封装
Feb 23 Javascript
使用jQuery.Qrcode插件在客户端动态生成二维码并添加自定义Logo
Sep 01 Javascript
webpack 插件html-webpack-plugin的具体使用
Apr 09 Javascript
在 Typescript 中使用可被复用的 Vue Mixin功能
Apr 17 Javascript
详解vue填坑之解决部分浏览器不支持pushState方法
Jul 12 Javascript
在js代码拼接dom对象到页面上的模板总结
Oct 21 Javascript
webpack.DefinePlugin与cross-env区别详解
Feb 23 Javascript
JS class语法糖的深入剖析
Jul 07 #Javascript
MutationObserver在页面水印实现起到的作用详解
Jul 07 #Javascript
js作用域及作用域链工作引擎
Promise静态四兄弟实现示例详解
Jul 07 #Javascript
Three.js实现雪糕地球的使用示例详解
二维码条形码生成的JavaScript脚本库
Jul 07 #Javascript
JS实现简单的九宫格抽奖
You might like
php环境配置 php5 mysql5 apache2 phpmyadmin安装与配置
2006/11/17 PHP
php 模拟get_headers函数的代码示例
2013/04/27 PHP
php 注册时输入信息验证器的实现详解
2013/07/05 PHP
PHP中fwrite与file_put_contents性能测试代码
2013/08/02 PHP
destoon实现VIP排名一直在前面排序的方法
2014/08/21 PHP
PHP简单实现生成txt文件到指定目录的方法
2016/04/25 PHP
中高级PHP程序员应该掌握哪些技术?
2016/09/23 PHP
PHP异常处理定义与使用方法分析
2017/07/25 PHP
2017年最好用的9个php开发工具推荐(超好用)
2017/10/23 PHP
PHP用swoole+websocket和redis实现web一对一聊天
2019/11/05 PHP
PHP论坛实现积分系统的思路代码详解
2020/06/01 PHP
google jQuery 引用文件,jQuery 引用地址集合(jquery 1.2.6至jquery1.5.2)
2011/04/24 Javascript
如何用jquery控制表格奇偶行及活动行颜色
2014/04/20 Javascript
node.js中的buffer.toString方法使用说明
2014/12/14 Javascript
javascript获取select值的方法分析
2015/07/02 Javascript
Bootstrap CSS组件之按钮组(btn-group)
2016/12/17 Javascript
vue项目关闭eslint校验
2018/03/21 Javascript
React学习笔记之高阶组件应用
2018/06/02 Javascript
JS/HTML5游戏常用算法之碰撞检测 地图格子算法实例详解
2018/12/12 Javascript
vue 中使用 watch 出现了如下的报错的原因分析
2019/05/21 Javascript
中级前端工程师必须要掌握的27个JavaScript 技巧(干货总结)
2019/09/23 Javascript
laydate只显示时分 不显示秒的功能实现方法
2019/09/28 Javascript
微信小程序scroll-view点击项自动居中效果的实现
2020/03/25 Javascript
跟老齐学Python之永远强大的函数
2014/09/14 Python
浅谈python的dataframe与series的创建方法
2018/11/12 Python
Eclipse配置python默认头过程图解
2020/04/26 Python
咖啡为什么会有酸味?你喝到的咖啡為什麼是酸的?
2021/03/17 冲泡冲煮
涂鸦板简单实现 Html5编写属于自己的画画板
2016/07/05 HTML / CSS
HTML5 在canvas中绘制矩形附效果图
2014/06/23 HTML / CSS
巴西最大的家电和百货零售商:Casas Bahia
2016/11/22 全球购物
店长岗位职责
2013/11/21 职场文书
大学生个人推荐信范文
2013/11/25 职场文书
商务日语专业毕业生自荐信
2014/03/27 职场文书
新学期开学演讲稿
2014/05/24 职场文书
公司股份转让协议书范本
2015/01/28 职场文书
CSS中妙用 drop-shadow 实现线条光影效果
2021/11/11 HTML / CSS