ES2015 (ES6) `class` 语法有什么好处? [英] What benefits does ES2015 (ES6) `class` syntax provide?

查看:24
本文介绍了ES2015 (ES6) `class` 语法有什么好处?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有很多关于 ES6 类的问题.

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

此外,class 是另一种 OOP 还是 JavaScript 的原型继承?我可以使用 .prototype 修改它吗?或者它只是同一个对象,但有两种不同的声明方式.

有速度优势吗?如果你有一个像大应用这样的大应用,也许更容易维护/理解?

解决方案

新的 class 语法主要是(尽管不是全部)语法糖(但是,你知道,好的em> 一种糖).它显着简化了构造函数的编写以及它们作为原型分配给它们创建的对象的对象,特别是在设置继承层次结构时,这在 ES5 语法中容易出错.但与旧方法不同的是,class 语法还为超级调用启用了 super.example()(众所周知,旧方法很难做到)以及 属性声明私有字段,以及私有方法(包括静态的).

(有时人们说如果你想对 ErrorArray 进行子类化,你必须使用 class 语法 [它们不能被正确地子类化在 ES5 中].那不是真的,你可以使用不同的 ES2015 特性,Reflect.construct [规范, MDN],如果你不想使用 class 语法.¹)

<块引用>

此外,class 是另一种 OOP 还是 JavaScript 的原型继承?

它与我们一直拥有的原型继承相同,只是语法更简洁、更方便且不易出错如果您喜欢使用构造函数(new Foo等),以及一些附加功能.

<块引用>

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

是的,一旦创建了类,您仍然可以在类的构造函数上修改 prototype 对象.例如,这是完全合法的:

class Foo {构造函数(名称){this.name = 名称;}测试1(){console.log("test1: name = "+ this.name);}}Foo.prototype.test2 = 函数(){console.log("test2: name = "+ this.name);};

<块引用>

有速度优势吗?

通过为此提供一个特定的习惯用法,我想可能引擎可以更好地优化工作.但他们已经非常擅长优化,我不希望有显着差异.关于 class 语法的一件事是,如果您使用 属性声明,您可以将对象在构造时经历的形状更改次数降至最低,这可以使解释和稍后编译代码的速度更快一些.但同样,它不会很大.

<块引用>

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

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

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

  • 语法更简单,更不容易出错.

  • 与旧语法相比,使用新语法设置继承层次结构要容易得多(而且更不容易出错).

  • class 可以保护您免受未将 new 与构造函数一起使用的常见错误(通过让构造函数抛出异常).

  • 使用新语法调用方法的父原型版本比旧语法(super.method() 而不是 ParentConstructor.prototype.method.call(this)Object.getPrototypeOf(Object.getPrototypeOf(this)).method.call(this)).

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

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

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

//***ES2015+**类人{构造函数(第一个,最后一个){this.first = 第一;this.last = 最后;}人方法(){//...}}类员工扩展人{构造函数(第一个,最后一个,位置){超级(第一个,最后一个);this.position = 位置;}员工方法(){//...}}班级经理扩展员工{构造函数(第一个,最后一个,位置,部门){超级(第一个,最后一个,位置);this.department = 部门;}人方法(){const 结果 = super.personMethod();//...将`result`用于某事...返回结果;}经理方法(){//...}}

示例:

//***ES2015+**类人{构造函数(第一个,最后一个){this.first = 第一;this.last = 最后;}人方法(){return `Result from personMethod: this.first = ${this.first}, this.last = ${this.last}`;}}类员工扩展人{构造函数(第一个,最后一个,位置){超级(第一个,最后一个);this.position = 位置;}人方法(){const 结果 = super.personMethod();return result + `, this.position = ${this.position}`;}员工方法(){//...}}班级经理扩展员工{构造函数(第一个,最后一个,位置,部门){超级(第一个,最后一个,位置);this.department = 部门;}人方法(){const 结果 = super.personMethod();return result + `, this.department = ${this.department}`;}经理方法(){//...}}const m = new Manager("Joe", "Bloggs", "Special Projects Manager", "Covert Ops");console.log(m.personMethod());

对比

//**ES5**var Person = function(first, last) {if (!(this instanceof Person)) {throw new Error(Person 是一个构造函数,使用 new");}this.first = 第一;this.last = 最后;};Person.prototype.personMethod = function() {//...};var Employee = 函数(第一个,最后一个,位置){if (!(this instanceof Employee)) {throw new Error(Employee 是一个构造函数,使用 new");}Person.call(this, first, last);this.position = 位置;};Employee.prototype = Object.create(Person.prototype);Employee.prototype.constructor = 员工;Employee.prototype.employeeMethod = function() {//...};var Manager = 函数(第一个,最后一个,职位,部门){if (!(this instanceof Manager)) {throw new Error(Manager 是一个构造函数,使用 new");}Employee.call(this, first, last, position);this.department = 部门;};Manager.prototype = Object.create(Employee.prototype);Manager.prototype.constructor = 经理;Manager.prototype.personMethod = function() {var 结果 = Employee.prototype.personMethod.call(this);//...将`result`用于某事...返回结果;};Manager.prototype.managerMethod = function() {//...};

现场示例:

//**ES5**var Person = function(first, last) {if (!(this instanceof Person)) {throw new Error("Person 是一个构造函数,使用 new");}this.first = 第一;this.last = 最后;};Person.prototype.personMethod = function() {return "Result from personMethod: this.first = " + this.first + ", this.last = " + this.last;};var Employee = 函数(第一个,最后一个,位置){if (!(this instanceof Employee)) {throw new Error("Employee 是一个构造函数,使用 new");}Person.call(this, first, last);this.position = 位置;};Employee.prototype = Object.create(Person.prototype);Employee.prototype.constructor = 员工;Employee.prototype.personMethod = function() {var 结果 = Person.prototype.personMethod.call(this);返回结果 + ", this.position = " + this.position;};Employee.prototype.employeeMethod = function() {//...};var Manager = 函数(第一个,最后一个,职位,部门){if (!(this instanceof Manager)) {throw new Error("Manager 是一个构造函数,使用 new");}Employee.call(this, first, last, position);this.department = 部门;};Manager.prototype = Object.create(Employee.prototype);Manager.prototype.constructor = 经理;Manager.prototype.personMethod = function() {var 结果 = Employee.prototype.personMethod.call(this);返回结果 + ", this.department = " + this.department;};Manager.prototype.managerMethod = function() {//...};var m = new Manager("Joe", "Bloggs", "Special Projects Manager", "Covert Ops");console.log(m.personMethod());

正如你所看到的,那里有很多重复和冗长的东西,很容易出错并且重新输入很无聊(我过去常常使用脚本,回到当天,在 class 之前来了).


¹ 如果您不想使用 class,您将如何使用 Reflect.construct 子类化 Error(例如)语法:

//创建错误子类:函数 MyError(...args) {返回 Reflect.construct(Error, args, this.constructor);}MyError.prototype = Object.create(Error.prototype);MyError.prototype.constructor = MyError;MyError.prototype.myMethod = function() {控制台日志(this.message);};//示例使用:函数外(){函数内部(){const e = new MyError("foo");console.log("调用 e.myMethod():");e.myMethod();console.log(`e instanceof MyError? ${e instanceof MyError}`);console.log(`e instanceof Error?${e instanceof Error}`);扔e;}内();}外层();

.as-console-wrapper {最大高度:100%!重要;}

I have many question about ES6 classes.

What's the benefit of using class syntax? I read that public/private/static will be part of ES7, is that a reason?

Moreover, is class a different kind of OOP or it still JavaScript's prototypical inheritance? Can I modify it using .prototype ? Or is it just the same object but two different ways to declare it.

Are there speed benefits? Maybe it's easier to maintain/understand if you have a big application like big app?

解决方案

The new class syntax is mostly, though not entirely, syntactic sugar (but, you know, the good kind of sugar). It markedly simplifies writing constructor functions and the objects they assign as prototypes to the objects they create, especially when setting up inheritance hierarchies, which was error-prone with the ES5 syntax. But unlike the old way, class syntax also enables super.example() for supercalls (which are notoriously hard to do the old way) as well as property declarations, private fields, and private methods (including static ones).

(Sometimes people say you have to use class syntax if you want to subclass Error or Array [which couldn't be properly subclassed in ES5]. That's not true, you can use a different ES2015 feature, Reflect.construct [spec, MDN], if you don't want to use class syntax.¹)

Moreover, is class a different kind of OOP or it still JavaScript's prototypical inheritance?

It's the same prototypical inheritance we've always had, just with cleaner, more convenient, and less error-prone syntax if you like using constructor functions (new Foo, etc.), plus some added features.

Can I modify it using .prototype?

Yes, you can still modify the prototype object on the class's constructor once you've created the class. E.g., this is perfectly legal:

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

Are there speed benefits?

By providing a specific idiom for this, I suppose it's possible that the engine may be able to do a better job optimizing. But they're awfully good at optimizing already, I wouldn't expect a significant difference. One thing in particular about class syntax is that if you use property declarations, you can minimize the number of shape changes an object goes through when being constructed, which can make interpreting and later compiling the code a bit faster. But again, it's not going to be big.

What benefits does ES2015 (ES6) class syntax provide?

Briefly: If you don't use constructor functions in the first place, preferring Object.create or similar, class isn't useful to you.

If you do use constructor functions, there are some benefits to class:

  • The syntax is simpler and less error-prone.

  • It's much easier (and again, less error-prone) to set up inheritance hierarchies using the new syntax than with the old.

  • class defends you from the common error of failing to use new with the constructor function (by having the constructor throw an exception).

  • Calling the parent prototype's version of a method is much simpler with the new syntax than the old (super.method() instead of ParentConstructor.prototype.method.call(this) or Object.getPrototypeOf(Object.getPrototypeOf(this)).method.call(this)).

  • Property declarations can make the shape of the instances being created clearer, separating it from the constructor logic.

  • You can use private fields and methods (both instance and static) with class syntax, and not with ES5 syntax.

Here's a syntax comparison (without private members) for a hierarchy:

// ***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() {
    // ...
};

Live Example:

// **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());

As you can see, there's lots of repeated and verbose stuff there which is easy to get wrong and boring to retype (I used to use a script for it, back in the day, before class came along).


¹ Here's how you'd use Reflect.construct to subclass Error (for instance) if you didn't want to use 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;
}

这篇关于ES2015 (ES6) `class` 语法有什么好处?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆