1
0
mirror of https://github.com/ruanyf/es6tutorial.git synced 2025-05-24 10:22:23 +00:00

docs(map): edit map

This commit is contained in:
ruanyf 2016-09-04 01:38:44 +08:00
parent cc6a82dcc3
commit d0fd2b623e
3 changed files with 105 additions and 17 deletions

View File

@ -66,7 +66,7 @@ class Bar {
var b = new Bar(); var b = new Bar();
b.doStuff() // "stuff" b.doStuff() // "stuff"
``` ```
.ant-menu-horizontal > li.ant-menu-item
构造函数的`prototype`属性在ES6的“类”上面继续存在。事实上类的所有方法都定义在类的`prototype`属性上面。 构造函数的`prototype`属性在ES6的“类”上面继续存在。事实上类的所有方法都定义在类的`prototype`属性上面。
```javascript ```javascript
@ -294,7 +294,7 @@ new Foo(); // ReferenceError
class Foo {} class Foo {}
``` ```
上面代码中,`Foo`类使用在前定义在后这样会报错因为ES6不会把变量声明提升到代码头部。这种规定的原因与下文要提到的继承有关,必须保证子类在父类之后定义。 上面代码中,`Foo`类使用在前定义在后这样会报错因为ES6不会把类的声明提升到代码头部。这种规定的原因与下文要提到的继承有关,必须保证子类在父类之后定义。
```javascript ```javascript
{ {
@ -304,11 +304,11 @@ class Foo {}
} }
``` ```
上面的代码不会报错,因为`class`继承`Foo`的时候,`Foo`已经有定义了。但是,如果存在Class的提升,上面代码就会报错,因为`class`会被提升到代码头部,而`let`命令是不提升的,所以导致`class`继承`Foo`的时候,`Foo`还没有定义。 上面的代码不会报错,因为`class`继承`Foo`的时候,`Foo`已经有定义了。但是,如果存在`class`的提升,上面代码就会报错,因为`class`会被提升到代码头部,而`let`命令是不提升的,所以导致`class`继承`Foo`的时候,`Foo`还没有定义。
### Class表达式 ### Class表达式
与函数一样,Class也可以使用表达式的形式定义。 与函数一样,也可以使用表达式的形式定义。
```javascript ```javascript
const MyClass = class Me { const MyClass = class Me {
@ -328,7 +328,7 @@ Me.name // ReferenceError: Me is not defined
上面代码表示,`Me`只在Class内部有定义。 上面代码表示,`Me`只在Class内部有定义。
如果Class内部没用到的话,可以省略`Me`,也就是可以写成下面的形式。 如果类的内部没用到的话,可以省略`Me`,也就是可以写成下面的形式。
```javascript ```javascript
const MyClass = class { /* ... */ }; const MyClass = class { /* ... */ };
@ -350,7 +350,7 @@ let person = new class {
person.sayName(); // "张三" person.sayName(); // "张三"
``` ```
上面代码中,person是一个立即执行的Class的实例。 上面代码中,`person`是一个立即执行的类的实例。
### 私有方法 ### 私有方法
@ -395,16 +395,16 @@ function bar(baz) {
上面代码中,`foo`是公有方法,内部调用了`bar.call(this, baz)`。这使得`bar`实际上成为了当前模块的私有方法。 上面代码中,`foo`是公有方法,内部调用了`bar.call(this, baz)`。这使得`bar`实际上成为了当前模块的私有方法。
还有一种方法是利用`Symbol`值的唯一性将私有方法的名字命名为一个Symbol值。 还有一种方法是利用`Symbol`值的唯一性,将私有方法的名字命名为一个`Symbol`值。
```javascript ```javascript
const bar = Symbol('bar'); const bar = Symbol('bar');
const snaf = Symbol('snaf'); const snaf = Symbol('snaf');
export default subclassFactory({ export default class myClass{
// 有方法 // 有方法
foo (baz) { foo(baz) {
this[bar](baz); this[bar](baz);
} }
@ -414,10 +414,82 @@ export default subclassFactory({
} }
// ... // ...
}); };
``` ```
上面代码中,`bar``snaf`都是Symbol值导致第三方无法获取到它们因此达到了私有方法和私有属性的效果。 上面代码中,`bar``snaf`都是`Symbol`值,导致第三方无法获取到它们,因此达到了私有方法和私有属性的效果。
### this的指向
类的方法内部如果含有`this`,它默认指向类的实例。但是,必须非常小心,一旦单独使用该方法,很可能报错。
```javascript
class Logger {
printName(name = 'there') {
this.print(`Hello ${name}`);
}
print(text) {
console.log(text);
}
}
const logger = new Logger();
const { printName } = logger;
printName(); // TypeError: Cannot read property 'print' of undefined
```
上面代码中,`printName`方法中的`this`,默认指向`Logger`类的实例。但是,如果将这个方法提取出来单独使用,`this`会指向该方法运行时所在的环境,因为找不到`print`方法而导致报错。
一个比较简单的解决方法是,在构造方法中绑定`this`,这样就不会找不到`print`方法了。
```javascript
class Logger {
constructor() {
this.printName = this.printName.bind(this);
}
// ...
}
```
另一种解决方法是使用箭头函数。
```javascript
class Logger {
constructor() {
this.printName = (name = 'there') => {
this.print(`Hello ${name}`);
};
}
// ...
}
```
还有一种解决方法是使用`Proxy`,获取方法的时候,自动绑定`this`
```javascript
function selfish (target) {
const cache = new WeakMap();
const handler = {
get (target, key) {
const value = Reflect.get(target, key);
if (typeof value !== 'function') {
return value;
}
if (!cache.has(value)) {
cache.set(value, value.bind(target));
}
return cache.get(value);
}
};
const proxy = new Proxy(target, handler);
return proxy;
}
const logger = selfish(new Logger());
```
### 严格模式 ### 严格模式
@ -427,7 +499,7 @@ export default subclassFactory({
### name属性 ### name属性
由于本质上ES6的Class只是ES5的构造函数的一层包装所以函数的许多特性都被Class继承包括`name`属性。 由于本质上ES6的只是ES5的构造函数的一层包装所以函数的许多特性都被`Class`继承,包括`name`属性。
```javascript ```javascript
class Point {} class Point {}

View File

@ -177,6 +177,7 @@
- Axel Rauschmayer, [ECMAScript 6: new OOP features besides classes](http://www.2ality.com/2014/12/es6-oop.html) - Axel Rauschmayer, [ECMAScript 6: new OOP features besides classes](http://www.2ality.com/2014/12/es6-oop.html)
- Axel Rauschmayer, [Classes in ECMAScript 6 (final semantics)](http://www.2ality.com/2015/02/es6-classes-final.html): Class语法的详细介绍和设计思想分析 - Axel Rauschmayer, [Classes in ECMAScript 6 (final semantics)](http://www.2ality.com/2015/02/es6-classes-final.html): Class语法的详细介绍和设计思想分析
- Eric Faust, [ES6 In Depth: Subclassing](https://hacks.mozilla.org/2015/08/es6-in-depth-subclassing/): Class语法的深入介绍 - Eric Faust, [ES6 In Depth: Subclassing](https://hacks.mozilla.org/2015/08/es6-in-depth-subclassing/): Class语法的深入介绍
- Nicolás Bevacqua, [Binding Methods to Class Instance Objects](https://ponyfoo.com/articles/binding-methods-to-class-instance-objects): 如何绑定类的实例中的this
## Decorator ## Decorator

View File

@ -412,9 +412,9 @@ data['[object HTMLDivElement]'] // "metadata"
```javascript ```javascript
var m = new Map(); var m = new Map();
var o = {p: "Hello World"}; var o = {p: 'Hello World'};
m.set(o, "content") m.set(o, 'content')
m.get(o) // "content" m.get(o) // "content"
m.has(o) // true m.has(o) // true
@ -427,7 +427,10 @@ m.has(o) // false
作为构造函数Map也可以接受一个数组作为参数。该数组的成员是一个个表示键值对的数组。 作为构造函数Map也可以接受一个数组作为参数。该数组的成员是一个个表示键值对的数组。
```javascript ```javascript
var map = new Map([['name', '张三'], ['title', 'Author']]); var map = new Map([
['name', '张三'],
['title', 'Author']
]);
map.size // 2 map.size // 2
map.has('name') // true map.has('name') // true
@ -449,6 +452,18 @@ var map = new Map();
items.forEach(([key, value]) => map.set(key, value)); items.forEach(([key, value]) => map.set(key, value));
``` ```
下面的例子中,字符串`true`和布尔值`true`是两个不同的键。
```javascript
var m = new Map([
[true, 'foo'],
['true', 'bar']
]);
m.get(true) // 'foo'
m.get('true') // 'bar'
```
如果对同一个键多次赋值,后面的值将覆盖前面的值。 如果对同一个键多次赋值,后面的值将覆盖前面的值。
```javascript ```javascript
@ -501,7 +516,7 @@ map.get(k2) // 222
由上可知Map的键实际上是跟内存地址绑定的只要内存地址不一样就视为两个键。这就解决了同名属性碰撞clash的问题我们扩展别人的库的时候如果使用对象作为键名就不用担心自己的属性与原作者的属性同名。 由上可知Map的键实际上是跟内存地址绑定的只要内存地址不一样就视为两个键。这就解决了同名属性碰撞clash的问题我们扩展别人的库的时候如果使用对象作为键名就不用担心自己的属性与原作者的属性同名。
如果Map的键是一个简单类型的值数字、字符串、布尔值则只要两个值严格相等Map将其视为一个键包括0和-0。另外虽然NaN不严格相等于自身但Map将其视为同一个键。 如果Map的键是一个简单类型的值数字、字符串、布尔值则只要两个值严格相等Map将其视为一个键包括`0``-0`。另外,虽然`NaN`不严格相等于自身但Map将其视为同一个键。
```javascript ```javascript
let map = new Map(); let map = new Map();