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

时间:2018-04-04 05:41:07

标签: javascript class

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

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

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

let user = new User("John");
user.sayHi();

VS。

class User {

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

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

}

let user = new User("John");
user.sayHi();

2 个答案:

答案 0 :(得分:2)

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

  • 不能在没有new的情况下调用类,但是作为构造函数的函数可以(并且它们的this将是错误的)

    'use strict';
    
    function Foo() {
        console.log(this);
    }
    
    class Bar {
        constructor() {
            console.log(this);
        }
    }
    
    Foo();
    Bar();

  • 类可以扩展比构造函数更多的类型(如函数和数组)

    '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)'))();

  • Classes的原型是他们的父母(他们继承静态属性);构造函数的编写者通常不会打扰这个

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

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

类的范围也类似于let / const(块范围,临时死区,不可重新声明),而不是类似var(函数范围,已提升)或类似函数声明(它是复杂)。

在您的示例中,另一个区别是sayHi是通过分配给新属性而非使用例如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);

答案 1 :(得分:1)

来自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();

透明到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();

所有ES6 +功能都可以转换成ES5--它完全是有效的语法糖。 ES5中仍然可以实现所有“新功能”。我认为,这称为“一个JavaScript”原则。