基于原型的类语法和JavaScript中的类语法有什么区别?

Lio*_*ang 3 javascript class

这些可互换的语法是否可以创建JS类?我已经习惯了 class语法,但不完全了解它们之间的区别。

function User(name) {
  this.name = name;
}

User.prototype.sayHi = function() {
  alert(this.name);
}

let user = new User("John");
user.sayHi();
Run Code Online (Sandbox Code Playgroud)

class User {

 constructor(name) {
   this.name = name;
 }

 sayHi() {
   alert(this.name);
 }

}

let user = new User("John");
user.sayHi();
Run Code Online (Sandbox Code Playgroud)

Ry-*_*Ry- 5

类和构造函数之间的主要区别是:

  • 没有类就不能调用类new,但是可以用作构造函数的函数可以(它们this将是错误的)

    'use strict';
    
    function Foo() {
        console.log(this);
    }
    
    class Bar {
        constructor() {
            console.log(this);
        }
    }
    
    Foo();
    Bar();
    Run Code Online (Sandbox Code Playgroud)

  • 与构造函数相比,类可以扩展更多类型(例如函数和数组)

    'use strict';
    
    function Foo(body) {
        Function.call(this, body);
    }
    
    Object.setPrototypeOf(Foo, Function);
    Foo.prototype = Object.create(Function.prototype);
    
    class Bar extends Function {}
    
    (new Bar('console.log(1)'))();
    (new Foo('console.log(1)'))();
    Run Code Online (Sandbox Code Playgroud)

  • 类的原型是它们的父级(它们继承静态属性)。构造函数的编写者通常不会为此而烦恼

  • 非类不能扩展类(因为它们不能调用父构造函数–请参见第一点)

    'use strict';
    
    class Bar extends Function {}
    
    function Foo() {
        Bar.call(this);
    }
    
    Object.setPrototypeOf(Foo, Bar);
    Foo.prototype = Object.create(Bar.prototype);
    
    void new Foo();
    Run Code Online (Sandbox Code Playgroud)

类的作用域也类似于let/ const(块作用域,时间死区,不可重声明),而不是像var(函数作用域,提升的)或类似函数声明(它很复杂)。

在您的示例中,另一个区别是sayHi通过分配给新属性而不是使用eg来定义的Object.defineProperty,因此该属性的属性与类示例中的属性不同sayHi,在前者中是可枚举的,而在后者中则没有。

function UserA(name) {
    this.name = name;
}

UserA.prototype.sayHi = function () {
    alert(this.name);
};

class UserB {
    constructor(name) {
        this.name = name;
    }

    sayHi() {
        alert(this.name);
    }
}

let a = [];
let b = [];

for (let key in new UserA()) a.push(key);
for (let key in new UserB()) b.push(key);

console.log(a, b);
Run Code Online (Sandbox Code Playgroud)


Ale*_*ied 3

来自MDN

ECMAScript 2015 中引入的 JavaScript 类主要是 JavaScript 现有的基于原型的继承的语法糖。类语法并未向 JavaScript 引入新的面向对象的继承模型。

您可以使用Babel REPL之类的工具来查看上面的 ES6 基于类的代码如何转换为 ES5 基于原型的代码:

ES6级

class User {

 constructor(name) {
   this.name = name;
 }

 sayHi() {
   alert(this.name);
 }

}

let user = new User("John");
user.sayHi();
Run Code Online (Sandbox Code Playgroud)

转换为 ES5

"use strict";

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var User = function () {
  function User(name) {
    _classCallCheck(this, User);

    this.name = name;
  }

  _createClass(User, [{
    key: "sayHi",
    value: function sayHi() {
      alert(this.name);
    }
  }]);

  return User;
}();

var user = new User("John");
user.sayHi();
Run Code Online (Sandbox Code Playgroud)

所有 ES6+ 功能都可以转译为 ES5——实际上,它就是语法糖。所有“新功能”仍然可以在 ES5 中实现。我认为这被称为“One JavaScript”学说。

  • *“所有 ES6+ 功能都可以转译为 ES5——实际上,它就是语法糖。所有“新功能”仍然可以在 ES5 中实现。”* 这不是真的。ES6 类的许多部分无法在 ES5 中复制;Babel 只是尽力而为。 (2认同)