Skip to content

第 7 期:ES5/ES6 的继承除了写法以外还有什么区别? #20

@alanchanzm

Description

@alanchanzm

来源:Understanding ECMAScript 6

  1. class 声明会提升,但不会初始化赋值。Foo 进入暂时性死区,类似于 letconst 声明变量。
const bar = new Bar(); // it's ok
function Bar() {
  this.bar = 42;
}

const foo = new Foo(); // ReferenceError: Foo is not defined
class Foo {
  constructor() {
    this.foo = 42;
  }
}
  1. class 声明内部会启用严格模式。
// 引用一个未声明的变量
function Bar() {
  baz = 42; // it's ok
}
const bar = new Bar();

class Foo {
  constructor() {
    fol = 42; // ReferenceError: fol is not defined
  }
}
const foo = new Foo();
  1. class 的所有方法(包括静态方法和实例方法)都是不可枚举的。
// 引用一个未声明的变量
function Bar() {
  this.bar = 42;
}
Bar.answer = function() {
  return 42;
};
Bar.prototype.print = function() {
  console.log(this.bar);
};
const barKeys = Object.keys(Bar); // ['answer']
const barProtoKeys = Object.keys(Bar.prototype); // ['print']

class Foo {
  constructor() {
    this.foo = 42;
  }
  static answer() {
    return 42;
  }
  print() {
    console.log(this.foo);
  }
}
const fooKeys = Object.keys(Foo); // []
const fooProtoKeys = Object.keys(Foo.prototype); // []
  1. class 的所有方法(包括静态方法和实例方法)都没有原型对象 prototype,所以也没有[[construct]],不能使用 new 来调用。
function Bar() {
  this.bar = 42;
}
Bar.prototype.print = function() {
  console.log(this.bar);
};

const bar = new Bar();
const barPrint = new bar.print(); // it's ok

class Foo {
  constructor() {
    this.foo = 42;
  }
  print() {
    console.log(this.foo);
  }
}
const foo = new Foo();
const fooPrint = new foo.print(); // TypeError: foo.print is not a constructor
  1. 必须使用 new 调用 class
function Bar() {
  this.bar = 42;
}
const bar = Bar(); // it's ok

class Foo {
  constructor() {
    this.foo = 42;
  }
}
const foo = Foo(); // TypeError: Class constructor Foo cannot be invoked without 'new'
  1. class 内部无法重写类名。
function Bar() {
  Bar = 'Baz'; // it's ok
  this.bar = 42;
}
const bar = new Bar();
// Bar: 'Baz'
// bar: Bar {bar: 42}  

class Foo {
  constructor() {
    this.foo = 42;
    Foo = 'Fol'; // TypeError: Assignment to constant variable
  }
}
const foo = new Foo();
Foo = 'Fol'; // it's ok

Activity

labike

labike commented on Feb 22, 2019

@labike

@alanchanzm 1. class 声明会提升 . 是不是写错了?
原文: Class declarations, unlike function declarations, are not hoisted.

alanchanzm

alanchanzm commented on Feb 22, 2019

@alanchanzm
Author

@alanchanzm 1. class 声明会提升 . 是不是写错了?
原文: Class declarations, unlike function declarations, are not hoisted.

@labike
原文有问题,class 是会提升的,其表现与letconst类似,变量名会进入TDZ。
看下例:如果没有提升,foo 会是块作用域外的Foo实例。但是由于提升的关系,块作用域内的Foo遮蔽了外层的同名函数。

var Foo = function() {
  this.foo = 21;
};

{
  const foo = new Foo(); // ReferenceError: Foo is not defined
  class Foo {
    constructor() {
      this.foo = 37;
    }
  }
}
changed the title [-]第 7 期:ES5/ES6 的继承除了写法以外还有什么区别?解答与一个疑惑[/-] [+]第 7 期:ES5/ES6 的继承除了写法以外还有什么区别?[/+] on Feb 22, 2019
labike

labike commented on Feb 23, 2019

@labike

@alanchanzm 我觉得不对吧

{
  const foo = new Foo(); // ReferenceError: Foo is not defined
  class Foo {
    constructor() {
      this.foo = 37;
    }
  }
}

class会提升这段代码就说不过去!
class

alanchanzm

alanchanzm commented on Feb 23, 2019

@alanchanzm
Author

@labike
可能是我们对「提升」的理解不同吧?我理解的「提升」和「赋值」是两个过程。
我拆解一下那个例子:

var Foo = function() { /** pass */ };

{
  // 「块作用域」内可以访问全局变量 Foo
  const foo = new Foo();
}
var Foo = function() { /** pass */ };

{
  // 「块作用域」内无法访问全局变量 Foo,因为它被本作用域内的 Foo 遮蔽了
  // 如果 class 不会提升的话,new Foo() 应该成功调用
  const foo = new Foo(); // ReferenceError: Foo is not defined
  class Foo{ /** pass */ }
}

类似于以下代码(但不等于):

var Foo = function() { /** pass */ };

{
  let Foo; // 区别在于此处 Foo 已经初始化为 undefined
  // 「块作用域」内无法访问全局变量 Foo,因为它被本作用域内的 Foo 遮蔽了
  const foo = new Foo(); 
  Foo = class { /** pass */}
}
XueSeason

XueSeason commented on Feb 23, 2019

@XueSeason

@alanchanzm 答了很多,而且很有帮助,但是离题了。

问题是继承的差异。

class Super {}
class Sub extends Super {}

const sub = new Sub();

Sub.__proto__ === Super;

子类可以直接通过 __proto__ 寻址到父类。

function Super() {}
function Sub() {}

Sub.prototype = new Super();
Sub.prototype.constructor = Sub;

var sub = new Sub();

Sub.__proto__ === Function.prototype;

而通过 ES5 的方式,Sub.__proto__ === Function.prototype

alanchanzm

alanchanzm commented on Feb 23, 2019

@alanchanzm
Author

@XueSeason 哈哈哈,审题不清,这轮面试要挂了。
再补充一点:
ES5 和 ES6 子类 this 生成顺序不同。ES5 的继承先生成了子类实例,再调用父类的构造函数修饰子类实例,ES6 的继承先生成父类实例,再调用子类的构造函数修饰父类实例。这个差别使得 ES6 可以继承内置对象。

function MyES5Array() {
  Array.call(this, arguments);
}

// it's useless
const arrayES5 = new MyES5Array(3); // arrayES5: MyES5Array {}

class MyES6Array extends Array {}

// it's ok
const arrayES6 = new MyES6Array(3); // arrayES6: MyES6Array(3) []
xiaofengqqcom123

xiaofengqqcom123 commented on Feb 27, 2019

@xiaofengqqcom123

因为this生成顺序不同,所以需要在constructor中,需要使用super()

xiaofengqqcom123

xiaofengqqcom123 commented on Feb 27, 2019

@xiaofengqqcom123

因为this生成顺序不同,所以需要在constructor中,需要使用super()

xiaofengqqcom123

xiaofengqqcom123 commented on Feb 27, 2019

@xiaofengqqcom123

因为this生成顺序不同,所以需要在constructor中,需要使用super()

xiaofengqqcom123

xiaofengqqcom123 commented on Feb 27, 2019

@xiaofengqqcom123

因为this生成顺序不同,所以需要在constructor中,需要使用super()

xiaofengqqcom123

xiaofengqqcom123 commented on Feb 27, 2019

@xiaofengqqcom123

因为this生成顺序不同,所以需要在constructor中,需要使用super()

xiaofengqqcom123

xiaofengqqcom123 commented on Feb 27, 2019

@xiaofengqqcom123

因为this生成顺序不同,所以需要在constructor中,需要使用super()

xiaofengqqcom123

xiaofengqqcom123 commented on Feb 27, 2019

@xiaofengqqcom123

因为this生成顺序不同,所以需要在constructor中,需要使用super()

xiaofengqqcom123

xiaofengqqcom123 commented on Feb 27, 2019

@xiaofengqqcom123

因为this生成顺序不同,所以需要在constructor中,需要使用super()

80 remaining items

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @whosesmile@yeesunday@rxdxxxx@cococa@XueSeason

        Issue actions

          第 7 期:ES5/ES6 的继承除了写法以外还有什么区别? · Issue #20 · Advanced-Frontend/Daily-Interview-Question