@@ -285,16 +285,26 @@ p3.printName() // "Oops"
285285
286286上面代码在` p1 ` 的原型上添加了一个` printName ` 方法,由于` p1 ` 的原型就是` p2 ` 的原型,因此` p2 ` 也可以调用这个方法。而且,此后新建的实例` p3 ` 也可以调用这个方法。这意味着,使用实例的` __proto__ ` 属性改写原型,必须相当谨慎,不推荐使用,因为这会改变Class的原始定义,影响到所有实例。
287287
288- ### name属性
288+ ### 不存在变量提升
289289
290- 由于本质上,ES6的Class只是ES5的构造函数的一层包装,所以函数的许多特性都被Class继承,包括 ` name ` 属性 。
290+ Class不存在变量提升(hoist),这一点与ES5完全不同 。
291291
292292``` javascript
293- class Point {}
294- Point . name // "Point"
293+ new Foo (); // ReferenceError
294+ class Foo {}
295295```
296296
297- ` name ` 属性总是返回紧跟在` class ` 关键字后面的类名。
297+ 上面代码中,` Foo ` 类使用在前,定义在后,这样会报错,因为ES6不会把变量声明提升到代码头部。这种规定的原因与下文要提到的继承有关,必须保证子类在父类之后定义。
298+
299+ ``` javascript
300+ {
301+ let Foo = class {};
302+ class Bar extends Foo {
303+ }
304+ }
305+ ```
306+
307+ 上面的代码不会报错,因为` class ` 继承` Foo ` 的时候,` Foo ` 已经有定义了。但是,如果存在Class的提升,上面代码就会报错,因为` class ` 会被提升到代码头部,而` let ` 命令是不提升的,所以导致` class ` 继承` Foo ` 的时候,` Foo ` 还没有定义。
298308
299309### Class表达式
300310
@@ -342,33 +352,90 @@ person.sayName(); // "张三"
342352
343353上面代码中,person是一个立即执行的Class的实例。
344354
345- ### 不存在变量提升
355+ ### 私有方法
346356
347- Class不存在变量提升(hoist),这一点与ES5完全不同。
357+ 私有方法是常见需求,但ES6不提供,只能通过变通方法模拟实现。
358+
359+ 一种做法是在命名上加以区别。
348360
349361``` javascript
350- new Foo (); // ReferenceError
351- class Foo {}
362+ class Widget {
363+
364+ // 公有方法
365+ foo (baz ) {
366+ this ._bar (baz);
367+ }
368+
369+ // 私有方法
370+ _bar (baz ) {
371+ return this .snaf = baz;
372+ }
373+
374+ // ...
375+ }
352376```
353377
354- 上面代码中,` Foo ` 类使用在前,定义在后,这样会报错,因为ES6不会把变量声明提升到代码头部。这种规定的原因与下文要提到的继承有关,必须保证子类在父类之后定义。
378+ 上面代码中,` _bar ` 方法前面的下划线,表示这是一个只限于内部使用的私有方法。但是,这种命名是不保险的,在类的外部,还是可以调用到这个方法。
379+
380+ 另一种方法就是索性将私有方法移出模块,因为模块内部的所有方法都是对外可见的。
355381
356382``` javascript
357- {
358- let Foo = class {};
359- class Bar extends Foo {
383+ class Widget {
384+ foo ( baz ) {
385+ bar . call ( this , baz);
360386 }
387+
388+ // ...
389+ }
390+
391+ function bar (baz ) {
392+ return this .snaf = baz;
361393}
362394```
363395
364- 上面的代码不会报错,因为` class ` 继承` Foo ` 的时候,` Foo ` 已经有定义了。但是,如果存在Class的提升,上面代码就会报错,因为` class ` 会被提升到代码头部,而` let ` 命令是不提升的,所以导致` class ` 继承` Foo ` 的时候,` Foo ` 还没有定义。
396+ 上面代码中,` foo ` 是公有方法,内部调用了` bar.call(this, baz) ` 。这使得` bar ` 实际上成为了当前模块的私有方法。
397+
398+ 还有一种方法是利用` Symbol ` 值的唯一性,将私有方法的名字命名为一个Symbol值。
399+
400+ ``` javascript
401+ const bar = Symbol (' bar' );
402+ const snaf = Symbol (' snaf' );
403+
404+ export default subclassFactory ({
405+
406+ // 共有方法
407+ foo (baz ) {
408+ this [bar](baz);
409+ }
410+
411+ // 私有方法
412+ [bar ](baz ) {
413+ return this [snaf] = baz;
414+ }
415+
416+ // ...
417+ });
418+ ```
419+
420+ 上面代码中,` bar ` 和` snaf ` 都是Symbol值,导致第三方无法获取到它们,因此达到了私有方法和私有属性的效果。
365421
366422### 严格模式
367423
368424类和模块的内部,默认就是严格模式,所以不需要使用` use strict ` 指定运行模式。只要你的代码写在类或模块之中,就只有严格模式可用。
369425
370426考虑到未来所有的代码,其实都是运行在模块之中,所以ES6实际上把整个语言升级到了严格模式。
371427
428+ ### name属性
429+
430+ 由于本质上,ES6的Class只是ES5的构造函数的一层包装,所以函数的许多特性都被Class继承,包括` name ` 属性。
431+
432+ ``` javascript
433+ class Point {}
434+ Point .name // "Point"
435+ ```
436+
437+ ` name ` 属性总是返回紧跟在` class ` 关键字后面的类名。
438+
372439## Class的继承
373440
374441### 基本用法
0 commit comments