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:
parent
cc6a82dcc3
commit
d0fd2b623e
@ -66,7 +66,7 @@ class Bar {
|
||||
var b = new Bar();
|
||||
b.doStuff() // "stuff"
|
||||
```
|
||||
|
||||
.ant-menu-horizontal > li.ant-menu-item
|
||||
构造函数的`prototype`属性,在ES6的“类”上面继续存在。事实上,类的所有方法都定义在类的`prototype`属性上面。
|
||||
|
||||
```javascript
|
||||
@ -294,7 +294,7 @@ new Foo(); // ReferenceError
|
||||
class Foo {}
|
||||
```
|
||||
|
||||
上面代码中,`Foo`类使用在前,定义在后,这样会报错,因为ES6不会把变量声明提升到代码头部。这种规定的原因与下文要提到的继承有关,必须保证子类在父类之后定义。
|
||||
上面代码中,`Foo`类使用在前,定义在后,这样会报错,因为ES6不会把类的声明提升到代码头部。这种规定的原因与下文要提到的继承有关,必须保证子类在父类之后定义。
|
||||
|
||||
```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也可以使用表达式的形式定义。
|
||||
与函数一样,类也可以使用表达式的形式定义。
|
||||
|
||||
```javascript
|
||||
const MyClass = class Me {
|
||||
@ -328,7 +328,7 @@ Me.name // ReferenceError: Me is not defined
|
||||
|
||||
上面代码表示,`Me`只在Class内部有定义。
|
||||
|
||||
如果Class内部没用到的话,可以省略`Me`,也就是可以写成下面的形式。
|
||||
如果类的内部没用到的话,可以省略`Me`,也就是可以写成下面的形式。
|
||||
|
||||
```javascript
|
||||
const MyClass = class { /* ... */ };
|
||||
@ -350,7 +350,7 @@ let person = new class {
|
||||
person.sayName(); // "张三"
|
||||
```
|
||||
|
||||
上面代码中,person是一个立即执行的Class的实例。
|
||||
上面代码中,`person`是一个立即执行的类的实例。
|
||||
|
||||
### 私有方法
|
||||
|
||||
@ -395,16 +395,16 @@ function bar(baz) {
|
||||
|
||||
上面代码中,`foo`是公有方法,内部调用了`bar.call(this, baz)`。这使得`bar`实际上成为了当前模块的私有方法。
|
||||
|
||||
还有一种方法是利用`Symbol`值的唯一性,将私有方法的名字命名为一个Symbol值。
|
||||
还有一种方法是利用`Symbol`值的唯一性,将私有方法的名字命名为一个`Symbol`值。
|
||||
|
||||
```javascript
|
||||
const bar = Symbol('bar');
|
||||
const snaf = Symbol('snaf');
|
||||
|
||||
export default subclassFactory({
|
||||
export default class myClass{
|
||||
|
||||
// 共有方法
|
||||
foo (baz) {
|
||||
// 公有方法
|
||||
foo(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属性
|
||||
|
||||
由于本质上,ES6的Class只是ES5的构造函数的一层包装,所以函数的许多特性都被Class继承,包括`name`属性。
|
||||
由于本质上,ES6的类只是ES5的构造函数的一层包装,所以函数的许多特性都被`Class`继承,包括`name`属性。
|
||||
|
||||
```javascript
|
||||
class Point {}
|
||||
|
@ -177,6 +177,7 @@
|
||||
- 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语法的详细介绍和设计思想分析
|
||||
- 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
|
||||
|
||||
|
@ -412,9 +412,9 @@ data['[object HTMLDivElement]'] // "metadata"
|
||||
|
||||
```javascript
|
||||
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.has(o) // true
|
||||
@ -427,7 +427,10 @@ m.has(o) // false
|
||||
作为构造函数,Map也可以接受一个数组作为参数。该数组的成员是一个个表示键值对的数组。
|
||||
|
||||
```javascript
|
||||
var map = new Map([['name', '张三'], ['title', 'Author']]);
|
||||
var map = new Map([
|
||||
['name', '张三'],
|
||||
['title', 'Author']
|
||||
]);
|
||||
|
||||
map.size // 2
|
||||
map.has('name') // true
|
||||
@ -449,6 +452,18 @@ var map = new Map();
|
||||
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
|
||||
@ -501,7 +516,7 @@ map.get(k2) // 222
|
||||
|
||||
由上可知,Map的键实际上是跟内存地址绑定的,只要内存地址不一样,就视为两个键。这就解决了同名属性碰撞(clash)的问题,我们扩展别人的库的时候,如果使用对象作为键名,就不用担心自己的属性与原作者的属性同名。
|
||||
|
||||
如果Map的键是一个简单类型的值(数字、字符串、布尔值),则只要两个值严格相等,Map将其视为一个键,包括0和-0。另外,虽然NaN不严格相等于自身,但Map将其视为同一个键。
|
||||
如果Map的键是一个简单类型的值(数字、字符串、布尔值),则只要两个值严格相等,Map将其视为一个键,包括`0`和`-0`。另外,虽然`NaN`不严格相等于自身,但Map将其视为同一个键。
|
||||
|
||||
```javascript
|
||||
let map = new Map();
|
||||
|
Loading…
x
Reference in New Issue
Block a user