深入理解ES6 009【学习笔记】

javascript中的类

function PersonType(name){
  this.name = name;
}
PersonType.prototype.sayName = function(){
  console.log(this.name)
}
var person = new PersonType("Nicholas")
person.sayName(); // outputs "Nicholas"

console.log(person instanceof PersonType) // true
console.log(person instanceof Object) // true

类声明

class PersonClass {
  // 等价于PersonType构造函数
  constructor(name){
    this.name = name
  }
  // 等价于PersonType.prototype.sayName
  sayName(){
    console.log(this.name)
  }
}
let person = new PersonClass("Nicholas");
person.sayName(); // outputs "Nicholas"

console.log(person instanceof PersonClass) //true
console.log(person instanceof Object) // true
console.log(typeof PersonClass) // function
console.log(typeof PersonClass.prototype.sayName) // function

class是语法糖,PersonClass声明实际上创建了一个具有构造函数方法行为的函数。通过Symbol.iterator定义生成器方法即可为定义默认迭代器

class Collection {
  constructor(){
    this.items = [];
  }

  *[Symbol.iterator](){
    yield *this.items.values()
  }
}
var collection = new Collection();
collection.items.push(1);
collection.items.push(2);
collection.items.push(3);

for(let x of collection){
  console.log(x);
}
// 输出:
// 1
// 2
// 3

静态成员

ES6类语法简化了创建静态成员的过程,在方法或访问器属性名前使用正式的静态注释即可。

class PersonClass {
  // 等价于PersonType构造函数
  constructor(name){
    this.name = name
  }
  // 等价于PersonType.prototype.sayName
  sayName(){
    console.log(this.name)
  }
  // 等价于等价于PersonType.create
  static create(name){
    return new PersonClass(name)
  }
}
let person = PersonClass.create("Nicholas")

继承与派生类

实现继承与自定义类型是一个不小的工作,严格意义上的继承需要多个步骤实现

function Rectangle(length,width){
  this.length = length;
  this.width = width;
}
Rectangle.prototype.getArea = function(){
  return this.length*this.width
}

function Square(length){
  Rectangle.call(this,length,length)
}

Square.prototype = Object.create(Rectangle.prototype,{
  constructor:{
    value:Square,
    enumerable:true,
    writable:true,
    configurable:true
  }
})
var square = new Square(3)
console.log(square.getArea()); // 9
console.log(square instanceof Square) // true
console.log(square instanceof Rectangle) // true

ES6使用extends关键字可以指定类继承的函数。原型会自动调整,通过调用super()方法即可访问基类的构造函数

class Rectangle {
  constructor(length,width){
    this.length = length;
    this.width = width
  }
  getArea(){
    return this.length*this.width;
  }
}
class Square extends Ractangle {
  constructor(length){
    // Rectangle.call(this,length,length)
    super(length,length)
  }
}
var square = new Square(3)
console.log(square.getArea()); // 9
console.log(square instanceof Square) // true
console.log(square instanceof Rectangle) // true

继承自其的类我们称之为派生类,如果在派生类中指定了构造函数必须调用super(),如果不这样做程序就会报错。

  • super
  • 只可在派生类的构造函数中使用super(),非派生类不可使用
  • 在构造函数中访问this之前一定要调用super,它负责初始化this,
  • 如果不想调用super(),则唯一的方法是让类的构造函数返回一个对象。

类方法遮蔽

派生类中的访问总会覆盖基类中的同名方法,如果想调用基类中的方法,我们可以使用super.getArea()

class Square extends Rectangle {
  constructor(length){
    super(length,length)
  }
  //覆盖并遮蔽Rectangle.prototype.getArea()方法
  getArea(){
    return this.length*this.length
  }
}

派生自表达式的类

ES6最强大的一面或许是从表达式导出类的功能了。只要表达式可以被解析为一个函数并且具有[[Construct]]属性和原型,那么就可以用extends进行派生。

内建对象的继承

class MyArray extends Array {
  // 空
}
var colors = new MyArray();
colors[0]="red"
console.log(colors.length) // 1
colors.length = 0
console.log(colors[0]); // undefined

MyArray直接继承自Array,其行为与Array也很相似,操作数值型属性会更新length属性,操作length属性也会更新数值型属性。于是可以正确地继承Array对象来创建自己的派生数组类型

Symbol.species属性

内建对象继承的一个实用之处是,原本在内建对象中返回实例自身的方法将自动返回派生类的实现。如你有一个继承自Array的派生类MyArray,那么像slice()这样的方法也会返回一个MyArray的实例

class MyArray extends Array{
  // 空
}
let items = new MyArray(1,2,3,4),
subitems = items.slice(1,3);
console.log(items instanceof MyArray); //true
console.log(subitems instanceof Myarray); // true

Symbol.species是诸多内部Symbol中的一个,它被用于定义返回函数的静态访问器属性。被返回的函数是一个构造函数,每当要在实例方法中(不是构造函数中)创建类的实例时必须使用这个构造函数。以下这些都是实现该属性定义的Symbol.species

  • Array
  • ArrayBuffer
  • Map
  • Promise
  • RegExp
  • Set
  • Typed arrays
// 几个内建类型像这样使用
class MyClass {
  static get [Symbol.species](){
    return this
  }
  constructor(value){
    this.value = value
  }
  clone(){
    return new this.constructor[Symbol.species](this.value)
  }
}

在构造函数中使用new.target

class Shape {
  constructor(){
    if(new.target === Shape){
      throw new Error("这个类是不能直接被实例化的")
    }
  }
}
class Rectangle extends Shape {
  constructor(length,width){
    super();
    this.length = length;
    this.width = width;
  }
}
let x = new Shap(); // 抛出错误
let y = new Rectangle(3,4) // 正常执行
console.log(y instanceof Shape) //true

主题测试文章,只做测试使用。发布者:Walker,转转请注明出处:https://walker-learn.xyz/archives/4335

(0)
Walker的头像Walker
上一篇 2025年11月24日 00:00
下一篇 2025年11月25日 14:00

相关推荐

  • 深入理解ES6 013【学习笔记】

    用模块封装代码 javascript用“共享一切”的方法加载代码,这是该语言中最容易出错且另人感到困惑的地方。其他语言使用诸如包这样的概念来定义代码作用域。在es6以前,在应用程序的每一个js中定义的一切都共享一个全局作用域。随着web应用程序变得更加复杂,js代码的使用量也开始增长,这一做法会引起问题,如命名冲突和安全问题。es6的一个目标是解决作用域问题…

    个人 2025年3月8日
    1.3K00
  • Go工程师体系课 013【学习笔记】

    订单事务 先扣库存 后扣库存 都会对库存和订单都会有影响, 所以要使用分布式事务 业务(下单不对付)业务问题 支付成功再扣减(下单了,支付时没库存了) 订单扣减,不支付(订单超时归还)【常用方式】 事务和分布式事务 1. 什么是事务? 事务(Transaction)是数据库管理系统中的一个重要概念,它是一组数据库操作的集合,这些操作要么全部成功执行,要么全部…

    个人 2025年11月25日
    40000
  • 深入理解ES6 002【学习笔记】

    字符串和正则表达式 字符串和正则表达式 Javascript字符串一直基于16位字符编码(UTF-16)进行构建。每16位的序列是一个编码单元(code unit),代表一个字符。length、charAt()等字符串属性和方法都基于这个编码单元构造的。Unicode的目标是为世界上每一个字符提供全球唯一的标识符。如果我们把字符长度限制在16位,码位数量将不…

    个人 2025年3月8日
    2.0K00
  • Go工程师体系课 018【学习笔记】

    API 网关与持续部署入门(Kong & Jenkins) 对应资料目录《第 2 章 Jenkins 入门》《第 3 章 通过 Jenkins 部署服务》,整理 Kong 与 Jenkins 在企业级持续交付中的实战路径。即便零基础,也能顺着步骤搭建出自己的网关 + 持续部署流水线。 课前导览:什么是 API 网关 API 网关位于客户端与后端微服务…

    个人 2025年11月25日
    28600
  • Nuxt3_扫盲 入门与原理介绍【学习笔记】

    Nuxt 3 入门与原理介绍 💡 什么是 Nuxt 3? Nuxt 3 是基于 Vue 3 和 Vite 打造的全栈前端框架,支持: 服务端渲染(SSR) 静态站点生成(SSG) 单页应用(SPA) 构建全栈应用(支持 API) Nuxt 3 是 Vue 的“加强版”,帮你简化项目结构和开发流程。 🔧 核心原理 功能 Nuxt 如何处理 ✅ 页面路由 自动根…

    个人 2025年4月6日
    2.2K00
简体中文 繁体中文 English