深入理解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://joyjs.cn/archives/4335

(0)
Walker的头像Walker
上一篇 2025年3月8日 12:52
下一篇 2025年3月8日 12:51

相关推荐

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

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

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

    es 安装 elasticsearch(理解为库) kibana(理解为连接工具)es 和 kibana(5601) 的版本要保持一致 MySQL 对照学习 Elasticsearch(ES) 术语对照 MySQL Elasticsearch database index(索引) table type(7.x 起固定为 _doc,8.x 彻底移除多 type…

    个人 2025年11月25日
    9600
  • Go工程师体系课 004【学习笔记】

    需求分析 后台管理系统 商品管理 商品列表 商品分类 品牌管理 品牌分类 订单管理 订单列表 用户信息管理 用户列表 用户地址 用户留言 轮播图管理 电商系统 登录页面 首页 商品搜索 商品分类导航 轮播图展示 推荐商品展示 商品详情页 商品图片展示 商品描述 商品规格选择 加入购物车 购物车 商品列表 数量调整 删除商品 结算功能 用户中心 订单中心 我的…

    个人 2025年11月25日
    10400
  • Node深入浅出(圣思园教育) 001【学习笔记】

    node 从异步编程范式理解 Node.js Node.js 的定位与核心思想 基于 V8 引擎 + libuv 事件驱动库,将 JavaScript 从浏览器带到服务器侧。 采用单线程事件循环处理 I/O,最大化利用 CPU 等待 I/O 的时间片,特别适合高并发、I/O 密集型场景。 “不要阻塞主线程”是设计哲学:尽量把耗时操作交给内核或线程池,回调结果…

    个人 2025年11月24日
    14400
  • 深入理解ES6 013【学习笔记】

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

    个人 2025年3月8日
    1.0K00

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信
欢迎🌹 Coding never stops, keep learning! 💡💻 光临🌹