ES2015 (ES6) `class` 语法有什么好处?

2024-04-15

我对 ES6 类有很多疑问。

使用有什么好处class句法?我读到 public/private/static 将成为 ES7 的一部分,这是一个原因吗?

而且,是class一种不同类型的 OOP 或者它仍然是 JavaScript 的原型继承?我可以使用修改它吗.prototype?或者它只是同一个对象,但声明它的方式不同。

有速度优势吗?如果您有像大应用程序这样的大型应用程序,也许更容易维护/理解?


The new class语法大部分(尽管不完全)是语法糖(但是,你知道,good一种糖)。它显着简化了构造函数的编写以及它们作为原型分配给它们创建的对象的对象,特别是在设置继承层次结构时,这在 ES5 语法中很容易出错。但与旧方式不同的是,class语法还允许super.example()对于超级调用(众所周知,用旧方法很难做到)以及财产申报 https://github.com/tc39/proposal-class-fields, 私人领域 https://github.com/tc39/proposal-class-fields, and 私有方法 https://github.com/tc39/proposal-private-methods(包括静态的 http://github.com/tc39/proposal-static-class-features/).

(有时人们说你必须使用class如果你想子类化语法Error or Array[在 ES5 中无法正确子类化]。这不是真的,你可以使用不同的 ES2015 功能,Reflect.construct [spec https://tc39.github.io/ecma262/#sec-reflect.construct, MDN https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect/construct],如果你不想使用class语法。

而且,是class一种不同类型的 OOP 或者它仍然是 JavaScript 的原型继承?

它与我们一直拥有的原型继承相同,只是具有更清晰、更方便且不易出错的语法if你喜欢使用构造函数(new Foo等),加上一些附加功能。

我可以使用修改它吗.prototype?

是的,您仍然可以修改prototype创建类后,在类的构造函数中添加对象。例如,这是完全合法的:

class Foo {
    constructor(name) {
        this.name = name;
    }
    
    test1() {
        console.log("test1: name = " + this.name);
    }
}
Foo.prototype.test2 = function() {
    console.log("test2: name = " + this.name);
};

有速度优势吗?

通过为此提供一个特定的习语,我想它是possible引擎可能能够更好地进行优化。但他们已经非常擅长优化,我不认为会有显着的差异。特别值得一提的是class语法是如果你使用财产申报 https://github.com/tc39/proposal-class-fields,你可以最小化形状变化对象在构造时会经历,这可以使解释和稍后编译代码更快一些。但话又说回来,规模不会很大。

ES2015(ES6)有什么好处class语法提供?

简而言之:如果您一开始不使用构造函数,则更喜欢Object.create或类似的,class对你没有用。

如果您确实使用构造函数,那么有一些好处class:

  • 语法更简单并且不易出错。

  • It's much使用新语法比使用旧语法更容易(并且更不容易出错)设置继承层次结构。

  • class保护您免受未能使用的常见错误的影响new与构造函数(通过让构造函数抛出异常)。

  • 使用新语法调用方法的父原型版本比旧语法要简单得多(super.method()代替ParentConstructor.prototype.method.call(this) or Object.getPrototypeOf(Object.getPrototypeOf(this)).method.call(this)).

  • 属性声明可以使创建的实例的形状更加清晰,将其与构造函数逻辑分开。

  • 您可以使用私有字段和方法(实例和静态)class语法,而不是 ES5 语法。

这是层次结构的语法比较(没有私有成员):

// ***ES2015+**
class Person {
    constructor(first, last) {
        this.first = first;
        this.last = last;
    }

    personMethod() {
        // ...
    }
}

class Employee extends Person {
    constructor(first, last, position) {
        super(first, last);
        this.position = position;
    }

    employeeMethod() {
        // ...
    }
}

class Manager extends Employee {
    constructor(first, last, position, department) {
        super(first, last, position);
        this.department = department;
    }

    personMethod() {
        const result = super.personMethod();
        // ...use `result` for something...
        return result;
    }

    managerMethod() {
        // ...
    }
}

Example:

// ***ES2015+**
class Person {
    constructor(first, last) {
        this.first = first;
        this.last = last;
    }

    personMethod() {
        return `Result from personMethod: this.first = ${this.first}, this.last = ${this.last}`;
    }
}

class Employee extends Person {
    constructor(first, last, position) {
        super(first, last);
        this.position = position;
    }

    personMethod() {
        const result = super.personMethod();
        return result + `, this.position = ${this.position}`;
    }

    employeeMethod() {
        // ...
    }
}

class Manager extends Employee {
    constructor(first, last, position, department) {
        super(first, last, position);
        this.department = department;
    }

    personMethod() {
        const result = super.personMethod();
        return result + `, this.department = ${this.department}`;
    }

    managerMethod() {
        // ...
    }
}

const m = new Manager("Joe", "Bloggs", "Special Projects Manager", "Covert Ops");
console.log(m.personMethod());

vs.

// **ES5**
var Person = function(first, last) {
    if (!(this instanceof Person)) {
        throw new Error("Person is a constructor function, use new with it");
    }
    this.first = first;
    this.last = last;
};

Person.prototype.personMethod = function() {
    // ...
};

var Employee = function(first, last, position) {
    if (!(this instanceof Employee)) {
        throw new Error("Employee is a constructor function, use new with it");
    }
    Person.call(this, first, last);
    this.position = position;
};
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
Employee.prototype.employeeMethod = function() {
    // ...
};

var Manager = function(first, last, position, department) {
    if (!(this instanceof Manager)) {
        throw new Error("Manager is a constructor function, use new with it");
    }
    Employee.call(this, first, last, position);
    this.department = department;
};
Manager.prototype = Object.create(Employee.prototype);
Manager.prototype.constructor = Manager;
Manager.prototype.personMethod = function() {
    var result = Employee.prototype.personMethod.call(this);
    // ...use `result` for something...
    return result;
};
Manager.prototype.managerMethod = function() {
    // ...
};

实例:

// **ES5**
var Person = function(first, last) {
    if (!(this instanceof Person)) {
        throw new Error("Person is a constructor function, use new with it");
    }
    this.first = first;
    this.last = last;
};

Person.prototype.personMethod = function() {
    return "Result from personMethod: this.first = " + this.first + ", this.last = " + this.last;
};

var Employee = function(first, last, position) {
    if (!(this instanceof Employee)) {
        throw new Error("Employee is a constructor function, use new with it");
    }
    Person.call(this, first, last);
    this.position = position;
};
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
Employee.prototype.personMethod = function() {
    var result = Person.prototype.personMethod.call(this);
    return result + ", this.position = " + this.position;
};
Employee.prototype.employeeMethod = function() {
    // ...
};

var Manager = function(first, last, position, department) {
    if (!(this instanceof Manager)) {
        throw new Error("Manager is a constructor function, use new with it");
    }
    Employee.call(this, first, last, position);
    this.department = department;
};
Manager.prototype = Object.create(Employee.prototype);
Manager.prototype.constructor = Manager;
Manager.prototype.personMethod = function() {
    var result = Employee.prototype.personMethod.call(this);
    return result + ", this.department = " + this.department;
};
Manager.prototype.managerMethod = function() {
    // ...
};        

var m = new Manager("Joe", "Bloggs", "Special Projects Manager", "Covert Ops");
console.log(m.personMethod());

正如你所看到的,那里有很多重复和冗长的东西,很容易出错并且重新输入很无聊(我以前使用过一个脚本,早在一天之前,之前class伴随着)。

我应该注意到,在 ES2015 代码中,Person函数的原型是Employee函数,但 ES5 代码中并非如此。在 ES5 中,没有办法做到这一点;所有功能都使用Function.prototype作为他们的原型。一些环境支持__proto__不过,伪属性可能允许改变这一点。在这些环境中,您可以这样做:

Employee.__proto__ = Person; // Was non-standard in ES5

如果出于某种原因你想这样做function语法而不是class在 ES2015+ 环境中,您可以使用标准Object.setPrototypeOf反而:

Object.setPrototypeOf(Employee, Person); // Standard ES2015+

但我看不出在 ES2015+ 环境中使用旧语法有任何强烈的动机(除了尝试了解管道的工作原理)。

(ES2015还定义了__proto__访问器属性 https://tc39.es/ecma262/multipage/fundamental-objects.html#sec-object.prototype.__proto__这是一个包装器Object.setPrototypeOf and Object.getPrototypeOf以便这些非标准环境中的代码成为标准,但它仅为遗留代码定义,并且是“规范可选”,意味着不需要环境来提供它。)


1 以下是您的使用方法Reflect.construct子类化Error(例如)如果你不想使用class syntax:

// Creating an Error subclass:
function MyError(...args) {
  return Reflect.construct(Error, args, this.constructor);
}
MyError.prototype = Object.create(Error.prototype);
MyError.prototype.constructor = MyError;
MyError.prototype.myMethod = function() {
  console.log(this.message);
};

// Example use:
function outer() {
  function inner() {
    const e = new MyError("foo");
    console.log("Callng e.myMethod():");
    e.myMethod();
    console.log(`e instanceof MyError? ${e instanceof MyError}`);
    console.log(`e instanceof Error? ${e instanceof Error}`);
    throw e;
  }
  inner();
}
outer();
.as-console-wrapper {
  max-height: 100% !important;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ES2015 (ES6) `class` 语法有什么好处? 的相关文章

  • 如何在 Chrome 中创建 TouchEvent?

    The W3C规范 http www w3 org TR 2011 WD touch events 20110505 idl def TouchEvent宣称initTouchEvent如下 void initTouchEvent in D
  • 调用“DOMNodeInserted”事件时添加元素

    我想在每个 喜欢 按钮 chrome 扩展 之后添加一个元素 由于帖子被添加到新闻提要而不刷新页面 我必须添加一个事件侦听器 DOMNodeInserted 但是当我尝试把after 里面的功能 它不起作用 Code contentArea
  • Typescript:按值检查对象是否存在于数组中

    我有这个数据 roles roleId 69801 role ADMIN roleId 69806 role SUPER ADMIN roleId 69805 role RB roleId 69804 role PILOTE roleId
  • 是否可以禁用特定 jQuery Ajax 调用的 Turbolinks 以防止页面刷新和滚动?

    我有一个 Rails 5 应用程序 非常想使用 Turbolinks 在应用程序中 有几个 PATCH ajax 调用 它们只是用新数据更新服务器 但不需要担心更新页面的状态 每当这些 ajax 请求返回时 Turbolinks 就会刷新页
  • 限制文本区域中每行的字符数

    我整个周末都在寻找解决这个难题的方法 但尚未找到一个可以正常工作的解决方案 我想要实现的是限制文本区域中每行的字符数 不是相同地限制它们 而是我选择的每行不同的字符数 例如 我只想在我的文本区域中包含 4 行 第 1 2 和 3 行将限制为
  • 如何将中间件绑定到socket.io中的事件

    现在您可以将中间件绑定到io use middleware 但这仅在建立套接字连接时触发 有没有办法在将其传递给事件句柄之前拦截它 就像在expressjs中一样 换句话说 In 快递 js你可以做 app get middleware1
  • 为什么 jQuery 点击事件会多次触发

    我这里有这个示例代码http jsfiddle net DBBUL 10 http jsfiddle net DBBUL 10 document ready function creategene click function confir
  • 将一个文本框的内容复制到另一个文本框

    假设在文本框中输入了一个条目 是否可以在第二个文本框中保留相同的输入文本 如果是这样 这是如何完成的
  • Flask wtf.quick_form 运行一些 javascript 并设置表单变量

    我正在创建博客文章 到目前为止已经使用普通的 html 表单完成了 我所做的一个有趣的想法是运行 javascript onclick 并使用页面中的额外数据在表单中设置一个隐藏变量 这很好地传递到服务器并通过 request form 获
  • 将音频与视频流合并 Node.js

    我正在创建 YouTube 视频下载器并且正在使用ytdl core库 它无法下载带有音频的高质量视频 因为 youtube 将其放在另一个文件中 但我需要将其全部下载到一个文件中 我已经这样做了 app get download asyn
  • 禁用 JavaScript 中的右键单击

    当我尝试禁用右键单击时 它不起作用 我尝试使用下面的代码 document onclick function e console log e button if e button 2 e preventDefault return fals
  • 保存/导出Chrome的JavaScript控制台输入历史记录

    无论如何 我可以保存或导出 JavaScript 控制台的历史记录吗 input 控制台历史记录 在 Google Chrome 中 我不想保存输出或错误 因此将鼠标悬停在控制台框上 右键单击并选择Save as 不是解决方案 我不想每次都
  • 如何改变HTML5视频的播放速度?

    如何更改 HTML5 中的视频播放速度 我查过视频标签的属性 https www w3schools com html html5 video asp在 w3school 但无法做到这一点 根据这个网站 http www chipwreck
  • 访问 TypeScript 数组的最后一个元素

    TypeScript 中有访问数组最后一个元素的符号吗 在 Ruby 中我可以说 array 1 有类似的东西吗 您可以通过索引访问数组元素 数组中最后一个元素的索引将是数组的长度 1 因为索引是从零开始的 这应该有效 var items
  • 如何滚动到div内的元素?

    我有一个滚动的div我想在点击它时发生一个事件 它会强制执行此操作div滚动以查看内部元素 我写的JavasCript是这样的 document getElementById chr scrollIntoView true 但这会在滚动时滚
  • 选中复选框时提交表单

    有没有办法在选中复选框时提交表单
  • Jquery,清除/清空 tbody 元素的所有内容?

    我认为这会相当简单 但似乎空方法无法清除我拥有的 tbody 如果有人知道执行此操作的正确方法 我将不胜感激 我只想删除 tbody 中包含的所有内容 到目前为止我正在尝试 tbodyid empty HTML table tbody tr
  • 需要js、d3 和 nvd3 集成

    我面临整合的问题要求 questions tagged requirejs with d3 questions tagged d3 and nvd3 questions tagged nvd3 我找到了一个使用 require 的简单解决方
  • 替换两个引号之间的字符串

    我想转动一根绳子str hello my name is michael what s your s into hello my name is span class name michael span 我怎样才能在 JavaScript
  • 在 javascript 中使用 xPath 解析具有默认命名空间的 XML

    我需要创建一个 XML xPath 解析器 所有解析都必须在客户端进行 使用 JavaScript 我创建了一个 javascript 来执行此操作 在默认名称空间发挥作用之前 一切看起来都正常 我根本无法查询具有默认命名空间的 XML 我

随机推荐

  • Google 地图本机应用程序 - 地图链接

    我想从我的移动网站在移动设备上打开本机谷歌地图应用程序 目前我正在使用该网址http maps google com maps q The 20 Diner 2027 20Main 20 街 20The 20 Village 电子邮件受保护
  • 适用于 iOS 的 Google 地图 SDK 要求 GoogleMaps.bundle 成为“复制捆绑包资源”下目标的一部分

    当我为 iOS 构建 GoogleMaps SDK 时 发生了这些错误 Terminating app due to uncaught exception GMSException reason Google Maps SDK for iO
  • 按产品类型查询/过滤 woocommerce 产品

    我添加了新的产品类型 例如here https wordpress stackexchange com a 120220 66786 现在我想展示该产品类型 这是我的查询 query args array post type gt prod
  • 谷歌驱动器API搜索具有给定文件夹ID的所有子文件

    这是我的文件夹在谷歌驱动器中的结构 Picture Date1 Pic1 png Pic2 png Date2 Pic3 png Pic4 png 现在我只有Picture文件夹 parentID文件夹 的ID 现在我想获取 Pic1 图片
  • 猫头鹰旋转木马外箭头导航

    我正在尝试为投资组合网站实现带有延迟加载图像的 Owl Carousel 但在定位导航按钮时遇到问题 理想情况下 我想将它们添加到位于图像中间的轮播的外部 我见过几个例子 这些例子是可行的 但就是无法理解 有人可以帮忙吗 我在这里添加了一个
  • 阻止 CMD 始终以管理员权限打开

    无论我如何打开它 cmd exe 总是以管理员权限打开 没有的话怎么打开呢 是否缺少某些注册表设置 即使我直接从运行对话框打开它或双击 system32 文件夹 它仍然会以管理员权限打开 Thanks Found out I was mis
  • 计算各自列中的关键字数量

    假设我有这样的数据 df lt read table text title date text blablabla 22 07 2023 blablablabla Blue blablabla blablabla 23 06 2023 ba
  • Swagger UI 正在将请求中的协议从 https 更改为 http

    在 swaggerUI 中 默认采用 http 但实际 API 将支持 https 一种可能的方式 将删除架构中的 http 但在本地无法测试 https 那么这个问题的可能解决方案是什么 任何人有想法请帮助我找到它 只需将其放入您的文档中
  • 更改 Java/Swing 中的助记符修饰键

    在 Swing 中设置焦点热键非常简单 tfldPlantsNeeded new JTextField FIELD LEN MED lblPlantsNeeded new JLabel Plants Needed lblPlantsNeed
  • 使用apache poi检测Excel中的隐藏单元格

    我们使用 apache poi 3 8 来解析 Excel 我们需要能够检测 并跳过 隐藏行 因为它们在我们的用例中往往包含垃圾数据 看起来这应该有效 row isFormatted row getRowStyle getHidden 但似
  • 抑制 Access VBA 中的写入冲突消息

    我的问题 我编写了一个存储过程来计算通过 Ms Access 前端 到 MSSQL2000 数据库 上的表单呈现的多个字段 我一打电话表格重新查询获取更改后的值 我可以看到我引起了写冲突的恼人消息 自您开始编辑以来 该记录已被其他用户更改
  • Fortran 指针多态性

    我正在尝试使用指针在对象之间创建链接 使用 Fortran 下面是代码片段 module base pars module type abstract public base pars end type end module module
  • Tensorflow:裁剪图像的最大中心方形区域

    我的网络拍摄尺寸的图像100 x 100像素 因此 我必须调整不同大小的数据集图像的大小 我希望能够从给定图像中提取最大的中心正方形区域 然后将其大小调整为100 x 100 更准确地说 假设图像的宽度为200像素和高度50像素 然后我想提
  • jwt:为什么我的令牌显示在 Chrome DevTools 中?

    我在 Express js 中有一个 API 可以创建博客文章并将其添加到我的数据库中 当我从 DevTools 内的 React 应用程序发出请求时 它将显示我的 JWT 我担心当我的网站上线时 人们可以看到我的令牌并从他们的网站发出添加
  • GIT 和推送忽略的文件

    使用 git 时必须遵循的具体程序是什么 我将给出我的程序 不知何故 它工作得不太顺利 cloned a repository works fine added settings files to gitignore to prevent
  • IntelliJ 结构搜索和替换问题

    有没有一种简单的方法来捕获类型 我似乎无法做一些基本的事情 例如并排使用变量表达式 例如 mapType mapEnd 做一个简单的替换 这可能有什么原因吗 也就是说 如果我有一个表达式 比如 s abc 我把它分成两个变量 s and a
  • 受密码保护的 pdf 中密码字段不可见

    我正在使用 PDF 套件框架来显示 编辑 pdf 文件 它在 macOS 10 12 上严重损坏 有时受密码保护的文件不显示密码字段 有时密码字段在普通文件中可见 我可以使用未记录的 API 来修复此问题 它的问题与隐藏 取消隐藏密码视图有
  • javax.net.ssl.SSLException:SSLSocketFactory 为 null

    我的以下代码有问题 System setProperty javax net ssl keyStoreType pkcs12 System setProperty javax net ssl trustStoreType jks Syste
  • 从核心数据中获取子项总和

    假设我有三个实体 Person 姓名 地址 对多工资 和 对多贷款 Salary 收入 税 相对 对一个人 Bills数量 相对 对一个人 如何执行获取结果如下 John Doe SUM gt 收入 SUM gt 金额 Eva Doe SU
  • ES2015 (ES6) `class` 语法有什么好处?

    我对 ES6 类有很多疑问 使用有什么好处class句法 我读到 public private static 将成为 ES7 的一部分 这是一个原因吗 而且 是class一种不同类型的 OOP 或者它仍然是 JavaScript 的原型继承