mirror of
https://github.com/ruanyf/es6tutorial.git
synced 2025-05-24 18:32:22 +00:00
Merge branch 'gh-pages' of github.com:ruanyf/es6tutorial into gh-pages
This commit is contained in:
commit
1764e48fdf
@ -14,7 +14,7 @@ function Point(x,y){
|
|||||||
|
|
||||||
Point.prototype.toString = function () {
|
Point.prototype.toString = function () {
|
||||||
return '(' + this.x + ', ' + this.y + ')';
|
return '(' + this.x + ', ' + this.y + ')';
|
||||||
}
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
上面这种写法跟传统的面向对象语言(比如C++和Java)差异很大,很容易让新学习这门语言的程序员感到困惑。
|
上面这种写法跟传统的面向对象语言(比如C++和Java)差异很大,很容易让新学习这门语言的程序员感到困惑。
|
||||||
@ -74,7 +74,7 @@ class Point {
|
|||||||
Point.prototype = {
|
Point.prototype = {
|
||||||
toString(){},
|
toString(){},
|
||||||
toValue(){}
|
toValue(){}
|
||||||
}
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
在类的实例上面调用方法,其实就是调用原型上的方法。
|
在类的实例上面调用方法,其实就是调用原型上的方法。
|
||||||
@ -100,7 +100,7 @@ class Point {
|
|||||||
Object.assign(Point.prototype, {
|
Object.assign(Point.prototype, {
|
||||||
toString(){},
|
toString(){},
|
||||||
toValue(){}
|
toValue(){}
|
||||||
})
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
`prototype`对象的`constructor`属性,直接指向“类”的本身,这与ES5的行为是一致的。
|
`prototype`对象的`constructor`属性,直接指向“类”的本身,这与ES5的行为是一致的。
|
||||||
@ -133,11 +133,11 @@ Object.getOwnPropertyNames(Point.prototype)
|
|||||||
```javascript
|
```javascript
|
||||||
var Point = function (x, y){
|
var Point = function (x, y){
|
||||||
// ...
|
// ...
|
||||||
}
|
};
|
||||||
|
|
||||||
Point.prototype.toString = function() {
|
Point.prototype.toString = function() {
|
||||||
// ...
|
// ...
|
||||||
}
|
};
|
||||||
|
|
||||||
Object.keys(Point.prototype)
|
Object.keys(Point.prototype)
|
||||||
// ["toString"]
|
// ["toString"]
|
||||||
@ -585,7 +585,7 @@ var obj = {
|
|||||||
toString() {
|
toString() {
|
||||||
return "MyObject: " + super.toString();
|
return "MyObject: " + super.toString();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
obj.toString(); // MyObject: [object Object]
|
obj.toString(); // MyObject: [object Object]
|
||||||
```
|
```
|
||||||
|
@ -94,12 +94,12 @@ import { mixins } from './mixins'
|
|||||||
|
|
||||||
const Foo = {
|
const Foo = {
|
||||||
foo() { console.log('foo') }
|
foo() { console.log('foo') }
|
||||||
}
|
};
|
||||||
|
|
||||||
@mixins(Foo)
|
@mixins(Foo)
|
||||||
class MyClass {}
|
class MyClass {}
|
||||||
|
|
||||||
let obj = new MyClass()
|
let obj = new MyClass();
|
||||||
obj.foo() // 'foo'
|
obj.foo() // 'foo'
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -108,7 +108,7 @@ obj.foo() // 'foo'
|
|||||||
```javascript
|
```javascript
|
||||||
const Foo = {
|
const Foo = {
|
||||||
foo() { console.log('foo') }
|
foo() { console.log('foo') }
|
||||||
}
|
};
|
||||||
|
|
||||||
class MyClass {}
|
class MyClass {}
|
||||||
|
|
||||||
@ -169,7 +169,7 @@ function nonenumerable(target, name, descriptor) {
|
|||||||
|
|
||||||
下面的`@log`修饰器,可以起到输出日志的作用。
|
下面的`@log`修饰器,可以起到输出日志的作用。
|
||||||
|
|
||||||
```bash
|
```javascript
|
||||||
class Math {
|
class Math {
|
||||||
@log
|
@log
|
||||||
add(a, b) {
|
add(a, b) {
|
||||||
@ -498,7 +498,7 @@ export function mixins(...list) {
|
|||||||
然后,就可以使用上面这个修饰器,为类“混入”各种方法。
|
然后,就可以使用上面这个修饰器,为类“混入”各种方法。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
import { mixins } from './mixins'
|
import { mixins } from './mixins';
|
||||||
|
|
||||||
const Foo = {
|
const Foo = {
|
||||||
foo() { console.log('foo') }
|
foo() { console.log('foo') }
|
||||||
@ -600,7 +600,7 @@ Trait也是一种修饰器,效果与Mixin类似,但是提供更多功能,
|
|||||||
下面采用[traits-decorator](https://github.com/CocktailJS/traits-decorator)这个第三方模块作为例子。这个模块提供的traits修饰器,不仅可以接受对象,还可以接受ES6类作为参数。
|
下面采用[traits-decorator](https://github.com/CocktailJS/traits-decorator)这个第三方模块作为例子。这个模块提供的traits修饰器,不仅可以接受对象,还可以接受ES6类作为参数。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
import { traits } from 'traits-decorator'
|
import { traits } from 'traits-decorator';
|
||||||
|
|
||||||
class TFoo {
|
class TFoo {
|
||||||
foo() { console.log('foo') }
|
foo() { console.log('foo') }
|
||||||
@ -608,12 +608,12 @@ class TFoo {
|
|||||||
|
|
||||||
const TBar = {
|
const TBar = {
|
||||||
bar() { console.log('bar') }
|
bar() { console.log('bar') }
|
||||||
}
|
};
|
||||||
|
|
||||||
@traits(TFoo, TBar)
|
@traits(TFoo, TBar)
|
||||||
class MyClass { }
|
class MyClass { }
|
||||||
|
|
||||||
let obj = new MyClass()
|
let obj = new MyClass();
|
||||||
obj.foo() // foo
|
obj.foo() // foo
|
||||||
obj.bar() // bar
|
obj.bar() // bar
|
||||||
```
|
```
|
||||||
@ -623,7 +623,7 @@ obj.bar() // bar
|
|||||||
Trait不允许“混入”同名方法。
|
Trait不允许“混入”同名方法。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
import {traits } from 'traits-decorator'
|
import { traits } from 'traits-decorator';
|
||||||
|
|
||||||
class TFoo {
|
class TFoo {
|
||||||
foo() { console.log('foo') }
|
foo() { console.log('foo') }
|
||||||
@ -632,7 +632,7 @@ class TFoo {
|
|||||||
const TBar = {
|
const TBar = {
|
||||||
bar() { console.log('bar') },
|
bar() { console.log('bar') },
|
||||||
foo() { console.log('foo') }
|
foo() { console.log('foo') }
|
||||||
}
|
};
|
||||||
|
|
||||||
@traits(TFoo, TBar)
|
@traits(TFoo, TBar)
|
||||||
class MyClass { }
|
class MyClass { }
|
||||||
@ -647,7 +647,7 @@ class MyClass { }
|
|||||||
一种解决方法是排除TBar的foo方法。
|
一种解决方法是排除TBar的foo方法。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
import { traits, excludes } from 'traits-decorator'
|
import { traits, excludes } from 'traits-decorator';
|
||||||
|
|
||||||
class TFoo {
|
class TFoo {
|
||||||
foo() { console.log('foo') }
|
foo() { console.log('foo') }
|
||||||
@ -656,12 +656,12 @@ class TFoo {
|
|||||||
const TBar = {
|
const TBar = {
|
||||||
bar() { console.log('bar') },
|
bar() { console.log('bar') },
|
||||||
foo() { console.log('foo') }
|
foo() { console.log('foo') }
|
||||||
}
|
};
|
||||||
|
|
||||||
@traits(TFoo, TBar::excludes('foo'))
|
@traits(TFoo, TBar::excludes('foo'))
|
||||||
class MyClass { }
|
class MyClass { }
|
||||||
|
|
||||||
let obj = new MyClass()
|
let obj = new MyClass();
|
||||||
obj.foo() // foo
|
obj.foo() // foo
|
||||||
obj.bar() // bar
|
obj.bar() // bar
|
||||||
```
|
```
|
||||||
@ -671,7 +671,7 @@ obj.bar() // bar
|
|||||||
另一种方法是为TBar的foo方法起一个别名。
|
另一种方法是为TBar的foo方法起一个别名。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
import { traits, alias } from 'traits-decorator'
|
import { traits, alias } from 'traits-decorator';
|
||||||
|
|
||||||
class TFoo {
|
class TFoo {
|
||||||
foo() { console.log('foo') }
|
foo() { console.log('foo') }
|
||||||
@ -680,12 +680,12 @@ class TFoo {
|
|||||||
const TBar = {
|
const TBar = {
|
||||||
bar() { console.log('bar') },
|
bar() { console.log('bar') },
|
||||||
foo() { console.log('foo') }
|
foo() { console.log('foo') }
|
||||||
}
|
};
|
||||||
|
|
||||||
@traits(TFoo, TBar::alias({foo: 'aliasFoo'}))
|
@traits(TFoo, TBar::alias({foo: 'aliasFoo'}))
|
||||||
class MyClass { }
|
class MyClass { }
|
||||||
|
|
||||||
let obj = new MyClass()
|
let obj = new MyClass();
|
||||||
obj.foo() // foo
|
obj.foo() // foo
|
||||||
obj.aliasFoo() // foo
|
obj.aliasFoo() // foo
|
||||||
obj.bar() // bar
|
obj.bar() // bar
|
||||||
|
@ -29,15 +29,15 @@ it.next() // { value: "a", done: false }
|
|||||||
it.next() // { value: "b", done: false }
|
it.next() // { value: "b", done: false }
|
||||||
it.next() // { value: undefined, done: true }
|
it.next() // { value: undefined, done: true }
|
||||||
|
|
||||||
function makeIterator(array){
|
function makeIterator(array) {
|
||||||
var nextIndex = 0;
|
var nextIndex = 0;
|
||||||
return {
|
return {
|
||||||
next: function(){
|
next: function() {
|
||||||
return nextIndex < array.length ?
|
return nextIndex < array.length ?
|
||||||
{value: array[nextIndex++], done: false} :
|
{value: array[nextIndex++], done: false} :
|
||||||
{value: undefined, done: true};
|
{value: undefined, done: true};
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -52,15 +52,15 @@ function makeIterator(array){
|
|||||||
对于遍历器对象来说,`done: false`和`value: undefined`属性都是可以省略的,因此上面的`makeIterator`函数可以简写成下面的形式。
|
对于遍历器对象来说,`done: false`和`value: undefined`属性都是可以省略的,因此上面的`makeIterator`函数可以简写成下面的形式。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
function makeIterator(array){
|
function makeIterator(array) {
|
||||||
var nextIndex = 0;
|
var nextIndex = 0;
|
||||||
return {
|
return {
|
||||||
next: function(){
|
next: function() {
|
||||||
return nextIndex < array.length ?
|
return nextIndex < array.length ?
|
||||||
{value: array[nextIndex++]} :
|
{value: array[nextIndex++]} :
|
||||||
{done: true};
|
{done: true};
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -74,14 +74,14 @@ it.next().value // '1'
|
|||||||
it.next().value // '2'
|
it.next().value // '2'
|
||||||
// ...
|
// ...
|
||||||
|
|
||||||
function idMaker(){
|
function idMaker() {
|
||||||
var index = 0;
|
var index = 0;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
next: function(){
|
next: function() {
|
||||||
return {value: index++, done: false};
|
return {value: index++, done: false};
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -166,31 +166,31 @@ for (var value of range(0, 3)) {
|
|||||||
下面是通过遍历器实现指针结构的例子。
|
下面是通过遍历器实现指针结构的例子。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
function Obj(value){
|
function Obj(value) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
this.next = null;
|
this.next = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Obj.prototype[Symbol.iterator] = function(){
|
Obj.prototype[Symbol.iterator] = function() {
|
||||||
var iterator = {
|
var iterator = {
|
||||||
next: next
|
next: next
|
||||||
};
|
};
|
||||||
|
|
||||||
var current = this;
|
var current = this;
|
||||||
|
|
||||||
function next(){
|
function next() {
|
||||||
if (current){
|
if (current) {
|
||||||
var value = current.value;
|
var value = current.value;
|
||||||
var done = current.next === null;
|
var done = current.next === null;
|
||||||
current = current.next;
|
current = current.next;
|
||||||
return {
|
return {
|
||||||
done: done,
|
done: done,
|
||||||
value: value
|
value: value
|
||||||
}
|
};
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
done: true
|
done: true
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return iterator;
|
return iterator;
|
||||||
@ -204,7 +204,7 @@ one.next = two;
|
|||||||
two.next = three;
|
two.next = three;
|
||||||
|
|
||||||
for (var i of one){
|
for (var i of one){
|
||||||
console.log(i)
|
console.log(i);
|
||||||
}
|
}
|
||||||
// 1
|
// 1
|
||||||
// 2
|
// 2
|
||||||
|
@ -91,7 +91,7 @@ export {firstName, lastName, year};
|
|||||||
export命令除了输出变量,还可以输出函数或类(class)。
|
export命令除了输出变量,还可以输出函数或类(class)。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
export function multiply (x, y) {
|
export function multiply(x, y) {
|
||||||
return x * y;
|
return x * y;
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
@ -350,7 +350,7 @@ import {crc32} from 'crc32';
|
|||||||
// modules.js
|
// modules.js
|
||||||
function add(x, y) {
|
function add(x, y) {
|
||||||
return x * y;
|
return x * y;
|
||||||
};
|
}
|
||||||
export {add as default};
|
export {add as default};
|
||||||
// 等同于
|
// 等同于
|
||||||
// export default add;
|
// export default add;
|
||||||
@ -402,7 +402,7 @@ export default 42;
|
|||||||
export default class { ... }
|
export default class { ... }
|
||||||
|
|
||||||
// main.js
|
// main.js
|
||||||
import MyClass from 'MyClass'
|
import MyClass from 'MyClass';
|
||||||
let o = new MyClass();
|
let o = new MyClass();
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -499,7 +499,7 @@ $ node main.js
|
|||||||
4
|
4
|
||||||
```
|
```
|
||||||
|
|
||||||
ES6模块的运行机制与CommonJS不一样,它遇到模块加载命令`import`时,不会去执行模块,而是只生成一个动态的只读引用。等到真的需要用到时,再到模块里面去取值,换句话说,ES6的输入有点像Unix系统的”符号连接“,原始值变了,`import`输入的值也会跟着变。因此,ES6模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。
|
ES6模块的运行机制与CommonJS不一样,它遇到模块加载命令`import`时,不会去执行模块,而是只生成一个动态的只读引用。等到真的需要用到时,再到模块里面去取值,换句话说,ES6的输入有点像Unix系统的“符号连接”,原始值变了,`import`输入的值也会跟着变。因此,ES6模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。
|
||||||
|
|
||||||
还是举上面的例子。
|
还是举上面的例子。
|
||||||
|
|
||||||
@ -545,7 +545,7 @@ baz
|
|||||||
|
|
||||||
上面代码表明,ES6模块不会缓存运行结果,而是动态地去被加载的模块取值,并且变量总是绑定其所在的模块。
|
上面代码表明,ES6模块不会缓存运行结果,而是动态地去被加载的模块取值,并且变量总是绑定其所在的模块。
|
||||||
|
|
||||||
由于ES6输入的模块变量,只是一个”符号连接“,所以这个变量是只读的,对它进行重新赋值会报错。
|
由于ES6输入的模块变量,只是一个“符号连接”,所以这个变量是只读的,对它进行重新赋值会报错。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// lib.js
|
// lib.js
|
||||||
@ -571,7 +571,7 @@ function C() {
|
|||||||
};
|
};
|
||||||
this.show = function () {
|
this.show = function () {
|
||||||
console.log(this.sum);
|
console.log(this.sum);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export let c = new C();
|
export let c = new C();
|
||||||
@ -616,7 +616,7 @@ var a = require('a');
|
|||||||
|
|
||||||
通常,“循环加载”表示存在强耦合,如果处理不好,还可能导致递归加载,使得程序无法执行,因此应该避免出现。
|
通常,“循环加载”表示存在强耦合,如果处理不好,还可能导致递归加载,使得程序无法执行,因此应该避免出现。
|
||||||
|
|
||||||
但是实际上,这是很难避免的,尤其是依赖关系复杂的大项目,很容易出现`a`依赖b,`b`依赖`c`,`c`又依赖`a`这样的情况。这意味着,模块加载机制必须考虑“循环加载”的情况。
|
但是实际上,这是很难避免的,尤其是依赖关系复杂的大项目,很容易出现`a`依赖`b`,`b`依赖`c`,`c`又依赖`a`这样的情况。这意味着,模块加载机制必须考虑“循环加载”的情况。
|
||||||
|
|
||||||
对于JavaScript语言来说,目前最常见的两种模块格式CommonJS和ES6,处理“循环加载”的方法是不一样的,返回的结果也不一样。
|
对于JavaScript语言来说,目前最常见的两种模块格式CommonJS和ES6,处理“循环加载”的方法是不一样的,返回的结果也不一样。
|
||||||
|
|
||||||
|
@ -146,7 +146,7 @@ var obj = {
|
|||||||
* m(){
|
* m(){
|
||||||
yield 'hello world';
|
yield 'hello world';
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
## 属性名表达式
|
## 属性名表达式
|
||||||
@ -233,9 +233,9 @@ var person = {
|
|||||||
console.log(this.name);
|
console.log(this.name);
|
||||||
},
|
},
|
||||||
get firstName() {
|
get firstName() {
|
||||||
return "Nicholas"
|
return "Nicholas";
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
person.sayName.name // "sayName"
|
person.sayName.name // "sayName"
|
||||||
person.firstName.name // "get firstName"
|
person.firstName.name // "get firstName"
|
||||||
@ -633,12 +633,12 @@ Reflect.ownKeys({ [Symbol()]:0, b:0, 10:0, 2:0, a:0 })
|
|||||||
// es6的写法
|
// es6的写法
|
||||||
var obj = {
|
var obj = {
|
||||||
method: function() { ... }
|
method: function() { ... }
|
||||||
}
|
};
|
||||||
obj.__proto__ = someOtherObj;
|
obj.__proto__ = someOtherObj;
|
||||||
|
|
||||||
// es5的写法
|
// es5的写法
|
||||||
var obj = Object.create(someOtherObj);
|
var obj = Object.create(someOtherObj);
|
||||||
obj.method = function() { ... }
|
obj.method = function() { ... };
|
||||||
```
|
```
|
||||||
|
|
||||||
该属性没有写入ES6的正文,而是写入了附录,原因是`__proto__`前后的双下划线,说明它本质上是一个内部属性,而不是一个正式的对外的API,只是由于浏览器广泛支持,才被加入了ES6。标准明确规定,只有浏览器必须部署这个属性,其他运行环境不一定需要部署,而且新的代码最好认为这个属性是不存在的。因此,无论从语义的角度,还是从兼容性的角度,都不要使用这个属性,而是使用下面的`Object.setPrototypeOf()`(写操作)、`Object.getPrototypeOf()`(读操作)、`Object.create()`(生成操作)代替。
|
该属性没有写入ES6的正文,而是写入了附录,原因是`__proto__`前后的双下划线,说明它本质上是一个内部属性,而不是一个正式的对外的API,只是由于浏览器广泛支持,才被加入了ES6。标准明确规定,只有浏览器必须部署这个属性,其他运行环境不一定需要部署,而且新的代码最好认为这个属性是不存在的。因此,无论从语义的角度,还是从兼容性的角度,都不要使用这个属性,而是使用下面的`Object.setPrototypeOf()`(写操作)、`Object.getPrototypeOf()`(读操作)、`Object.create()`(生成操作)代替。
|
||||||
@ -662,7 +662,7 @@ Object.defineProperty(Object.prototype, '__proto__', {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
let status = Reflect.setPrototypeOf(this, proto);
|
let status = Reflect.setPrototypeOf(this, proto);
|
||||||
if (! status) {
|
if (!status) {
|
||||||
throw new TypeError();
|
throw new TypeError();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -756,7 +756,7 @@ Object.keys(obj)
|
|||||||
目前,ES7有一个[提案](https://github.com/tc39/proposal-object-values-entries),引入了跟`Object.keys`配套的`Object.values`和`Object.entries`。
|
目前,ES7有一个[提案](https://github.com/tc39/proposal-object-values-entries),引入了跟`Object.keys`配套的`Object.values`和`Object.entries`。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
let {keys, values, entries} = Object;
|
let {keys, values, entries} = Object;
|
||||||
let obj = { a: 1, b: 2, c: 3 };
|
let obj = { a: 1, b: 2, c: 3 };
|
||||||
|
|
||||||
for (let key of keys(obj)) {
|
for (let key of keys(obj)) {
|
||||||
@ -943,9 +943,9 @@ var o = Object.create({ x: 1, y: 2 });
|
|||||||
o.z = 3;
|
o.z = 3;
|
||||||
|
|
||||||
let { x, ...{ y, z } } = o;
|
let { x, ...{ y, z } } = o;
|
||||||
x; // 1
|
x // 1
|
||||||
y; // undefined
|
y // undefined
|
||||||
z; // 3
|
z // 3
|
||||||
```
|
```
|
||||||
|
|
||||||
上面代码中,变量`x`是单纯的解构赋值,所以可以读取继承的属性;Rest解构赋值产生的变量`y`和`z`,只能读取对象自身的属性,所以只有变量`z`可以赋值成功。
|
上面代码中,变量`x`是单纯的解构赋值,所以可以读取继承的属性;Rest解构赋值产生的变量`y`和`z`,只能读取对象自身的属性,所以只有变量`z`可以赋值成功。
|
||||||
@ -1010,7 +1010,7 @@ let aWithOverrides = Object.assign({}, a, { x: 1, y: 2 });
|
|||||||
```javascript
|
```javascript
|
||||||
let newVersion = {
|
let newVersion = {
|
||||||
...previousVersion,
|
...previousVersion,
|
||||||
name: 'New Name', // Override the name property
|
name: 'New Name' // Override the name property
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -1074,7 +1074,7 @@ ES7有一个提案,提出了`Object.getOwnPropertyDescriptors`方法,返回
|
|||||||
```javascript
|
```javascript
|
||||||
const obj = {
|
const obj = {
|
||||||
foo: 123,
|
foo: 123,
|
||||||
get bar() { return 'abc' },
|
get bar() { return 'abc' }
|
||||||
};
|
};
|
||||||
|
|
||||||
Object.getOwnPropertyDescriptors(obj)
|
Object.getOwnPropertyDescriptors(obj)
|
||||||
|
@ -35,7 +35,7 @@ obj.count = 1
|
|||||||
ES6原生提供Proxy构造函数,用来生成Proxy实例。
|
ES6原生提供Proxy构造函数,用来生成Proxy实例。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var proxy = new Proxy(target, handler)
|
var proxy = new Proxy(target, handler);
|
||||||
```
|
```
|
||||||
|
|
||||||
Proxy对象的所有用法,都是上面这种形式,不同的只是`handler`参数的写法。其中,`new Proxy()`表示生成一个Proxy实例,target参数表示所要拦截的目标对象,`handler`参数也是一个对象,用来定制拦截行为。
|
Proxy对象的所有用法,都是上面这种形式,不同的只是`handler`参数的写法。其中,`new Proxy()`表示生成一个Proxy实例,target参数表示所要拦截的目标对象,`handler`参数也是一个对象,用来定制拦截行为。
|
||||||
@ -73,7 +73,7 @@ target.a // "b"
|
|||||||
一个技巧是将Proxy对象,设置到`object.proxy`属性,从而可以在`object`对象上调用。
|
一个技巧是将Proxy对象,设置到`object.proxy`属性,从而可以在`object`对象上调用。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var object = { proxy: new Proxy(target, handler) }
|
var object = { proxy: new Proxy(target, handler) };
|
||||||
```
|
```
|
||||||
|
|
||||||
Proxy实例也可以作为其他对象的原型对象。
|
Proxy实例也可以作为其他对象的原型对象。
|
||||||
@ -97,15 +97,15 @@ obj.time // 35
|
|||||||
var handler = {
|
var handler = {
|
||||||
get: function(target, name) {
|
get: function(target, name) {
|
||||||
if (name === 'prototype') return Object.prototype;
|
if (name === 'prototype') return Object.prototype;
|
||||||
return 'Hello, '+ name;
|
return 'Hello, ' + name;
|
||||||
},
|
},
|
||||||
apply: function(target, thisBinding, args) { return args[0]; },
|
apply: function(target, thisBinding, args) { return args[0]; },
|
||||||
construct: function(target, args) { return args[1]; }
|
construct: function(target, args) { return args[1]; }
|
||||||
};
|
};
|
||||||
|
|
||||||
var fproxy = new Proxy(function(x,y) {
|
var fproxy = new Proxy(function(x, y) {
|
||||||
return x+y;
|
return x + y;
|
||||||
}, handler);
|
}, handler);
|
||||||
|
|
||||||
fproxy(1,2); // 1
|
fproxy(1,2); // 1
|
||||||
new fproxy(1,2); // 2
|
new fproxy(1,2); // 2
|
||||||
@ -279,19 +279,6 @@ pipe(3).double.pow.reverseInt.get; // 63
|
|||||||
下面的例子则是利用`get`拦截,实现一个生成各种DOM节点的通用函数`dom`。
|
下面的例子则是利用`get`拦截,实现一个生成各种DOM节点的通用函数`dom`。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
const el = dom.div({},
|
|
||||||
'Hello, my name is ',
|
|
||||||
dom.a({href: '//example.com'}, 'Mark'),
|
|
||||||
'. I like:',
|
|
||||||
dom.ul({},
|
|
||||||
dom.li({}, 'The web'),
|
|
||||||
dom.li({}, 'Food'),
|
|
||||||
dom.li({}, '…actually that\'s it')
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
document.body.appendChild(el);
|
|
||||||
|
|
||||||
const dom = new Proxy({}, {
|
const dom = new Proxy({}, {
|
||||||
get(target, property) {
|
get(target, property) {
|
||||||
return function(attrs = {}, ...children) {
|
return function(attrs = {}, ...children) {
|
||||||
@ -309,6 +296,19 @@ const dom = new Proxy({}, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const el = dom.div({},
|
||||||
|
'Hello, my name is ',
|
||||||
|
dom.a({href: '//example.com'}, 'Mark'),
|
||||||
|
'. I like:',
|
||||||
|
dom.ul({},
|
||||||
|
dom.li({}, 'The web'),
|
||||||
|
dom.li({}, 'Food'),
|
||||||
|
dom.li({}, '…actually that\'s it')
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
document.body.appendChild(el);
|
||||||
```
|
```
|
||||||
|
|
||||||
### set()
|
### set()
|
||||||
@ -357,7 +357,7 @@ var handler = {
|
|||||||
invariant(key, 'set');
|
invariant(key, 'set');
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
function invariant (key, action) {
|
function invariant (key, action) {
|
||||||
if (key[0] === '_') {
|
if (key[0] === '_') {
|
||||||
throw new Error(`Invalid attempt to ${action} private "${key}" property`);
|
throw new Error(`Invalid attempt to ${action} private "${key}" property`);
|
||||||
@ -382,7 +382,7 @@ var handler = {
|
|||||||
apply (target, ctx, args) {
|
apply (target, ctx, args) {
|
||||||
return Reflect.apply(...arguments);
|
return Reflect.apply(...arguments);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
`apply`方法可以接受三个参数,分别是目标对象、目标对象的上下文对象(`this`)和目标对象的参数数组。
|
`apply`方法可以接受三个参数,分别是目标对象、目标对象的上下文对象(`this`)和目标对象的参数数组。
|
||||||
@ -461,7 +461,7 @@ var p = new Proxy(obj, {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
"a" in p; // TypeError is thrown
|
"a" in p // TypeError is thrown
|
||||||
```
|
```
|
||||||
|
|
||||||
上面代码中,`obj`对象禁止扩展,结果使用`has`拦截就会报错。
|
上面代码中,`obj`对象禁止扩展,结果使用`has`拦截就会报错。
|
||||||
@ -475,7 +475,7 @@ var handler = {
|
|||||||
construct (target, args) {
|
construct (target, args) {
|
||||||
return new target(...args);
|
return new target(...args);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
下面是一个例子。
|
下面是一个例子。
|
||||||
@ -515,15 +515,15 @@ var handler = {
|
|||||||
invariant(key, 'delete');
|
invariant(key, 'delete');
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
function invariant (key, action) {
|
function invariant (key, action) {
|
||||||
if (key[0] === '_') {
|
if (key[0] === '_') {
|
||||||
throw new Error(`Invalid attempt to ${action} private "${key}" property`);
|
throw new Error(`Invalid attempt to ${action} private "${key}" property`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var target = { _prop: 'foo' }
|
var target = { _prop: 'foo' };
|
||||||
var proxy = new Proxy(target, handler)
|
var proxy = new Proxy(target, handler);
|
||||||
delete proxy._prop
|
delete proxy._prop
|
||||||
// Error: Invalid attempt to delete private "_prop" property
|
// Error: Invalid attempt to delete private "_prop" property
|
||||||
```
|
```
|
||||||
@ -537,11 +537,11 @@ delete proxy._prop
|
|||||||
```javascript
|
```javascript
|
||||||
var handler = {
|
var handler = {
|
||||||
defineProperty (target, key, descriptor) {
|
defineProperty (target, key, descriptor) {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
var target = {}
|
var target = {};
|
||||||
var proxy = new Proxy(target, handler)
|
var proxy = new Proxy(target, handler);
|
||||||
proxy.foo = 'bar'
|
proxy.foo = 'bar'
|
||||||
// TypeError: proxy defineProperty handler returned false for property '"foo"'
|
// TypeError: proxy defineProperty handler returned false for property '"foo"'
|
||||||
```
|
```
|
||||||
@ -557,9 +557,9 @@ var handler = {
|
|||||||
enumerate (target) {
|
enumerate (target) {
|
||||||
return Object.keys(target).filter(key => key[0] !== '_')[Symbol.iterator]();
|
return Object.keys(target).filter(key => key[0] !== '_')[Symbol.iterator]();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
var target = { prop: 'foo', _bar: 'baz', _prop: 'foo' }
|
var target = { prop: 'foo', _bar: 'baz', _prop: 'foo' };
|
||||||
var proxy = new Proxy(target, handler)
|
var proxy = new Proxy(target, handler);
|
||||||
for (let key in proxy) {
|
for (let key in proxy) {
|
||||||
console.log(key);
|
console.log(key);
|
||||||
// "prop"
|
// "prop"
|
||||||
@ -607,11 +607,11 @@ for (var x in p) {} // 报错
|
|||||||
var handler = {
|
var handler = {
|
||||||
getOwnPropertyDescriptor (target, key) {
|
getOwnPropertyDescriptor (target, key) {
|
||||||
if (key[0] === '_') {
|
if (key[0] === '_') {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
return Object.getOwnPropertyDescriptor(target, key)
|
return Object.getOwnPropertyDescriptor(target, key);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
var target = { _foo: 'bar', baz: 'tar' };
|
var target = { _foo: 'bar', baz: 'tar' };
|
||||||
var proxy = new Proxy(target, handler);
|
var proxy = new Proxy(target, handler);
|
||||||
Object.getOwnPropertyDescriptor(proxy, 'wat')
|
Object.getOwnPropertyDescriptor(proxy, 'wat')
|
||||||
@ -682,7 +682,7 @@ var p = new Proxy({}, {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Object.isExtensible(p); // 报错
|
Object.isExtensible(p) // 报错
|
||||||
```
|
```
|
||||||
|
|
||||||
### ownKeys()
|
### ownKeys()
|
||||||
@ -732,7 +732,7 @@ for (let key of Object.keys(proxy)) {
|
|||||||
|
|
||||||
`preventExtensions`方法拦截`Object.preventExtensions()`。该方法必须返回一个布尔值。
|
`preventExtensions`方法拦截`Object.preventExtensions()`。该方法必须返回一个布尔值。
|
||||||
|
|
||||||
这个方法有一个限制,只有当`Object.isExtensible(proxy)`为`false`(即不可扩展)时,`proxy.preventExtensions`才能返回true,否则会报错。
|
这个方法有一个限制,只有当`Object.isExtensible(proxy)`为`false`(即不可扩展)时,`proxy.preventExtensions`才能返回`true`,否则会报错。
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var p = new Proxy({}, {
|
var p = new Proxy({}, {
|
||||||
@ -741,7 +741,7 @@ var p = new Proxy({}, {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Object.preventExtensions(p); // 报错
|
Object.preventExtensions(p) // 报错
|
||||||
```
|
```
|
||||||
|
|
||||||
上面代码中,`proxy.preventExtensions`方法返回`true`,但这时`Object.isExtensible(proxy)`会返回`true`,因此报错。
|
上面代码中,`proxy.preventExtensions`方法返回`true`,但这时`Object.isExtensible(proxy)`会返回`true`,因此报错。
|
||||||
@ -773,7 +773,7 @@ var handler = {
|
|||||||
setPrototypeOf (target, proto) {
|
setPrototypeOf (target, proto) {
|
||||||
throw new Error('Changing the prototype is forbidden');
|
throw new Error('Changing the prototype is forbidden');
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
var proto = {};
|
var proto = {};
|
||||||
var target = function () {};
|
var target = function () {};
|
||||||
var proxy = new Proxy(target, handler);
|
var proxy = new Proxy(target, handler);
|
||||||
@ -915,7 +915,7 @@ Reflect.apply(Math.floor, undefined, [1.75]) // 1
|
|||||||
var obj = {
|
var obj = {
|
||||||
get foo() { return this.bar(); },
|
get foo() { return this.bar(); },
|
||||||
bar: function() { ... }
|
bar: function() { ... }
|
||||||
}
|
};
|
||||||
|
|
||||||
// 下面语句会让 this.bar()
|
// 下面语句会让 this.bar()
|
||||||
// 变成调用 wrapper.bar()
|
// 变成调用 wrapper.bar()
|
||||||
|
@ -11,7 +11,7 @@ Set本身是一个构造函数,用来生成Set数据结构。
|
|||||||
```javascript
|
```javascript
|
||||||
var s = new Set();
|
var s = new Set();
|
||||||
|
|
||||||
[2, 3, 5, 4, 5, 2, 2].map(x => s.add(x))
|
[2, 3, 5, 4, 5, 2, 2].map(x => s.add(x));
|
||||||
|
|
||||||
for (let i of s) {
|
for (let i of s) {
|
||||||
console.log(i);
|
console.log(i);
|
||||||
@ -25,7 +25,7 @@ Set函数可以接受一个数组(或类似数组的对象)作为参数,
|
|||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// 例一
|
// 例一
|
||||||
var set = new Set([1, 2, 3, 4, 4])
|
var set = new Set([1, 2, 3, 4, 4]);
|
||||||
[...set]
|
[...set]
|
||||||
// [1, 2, 3, 4]
|
// [1, 2, 3, 4]
|
||||||
|
|
||||||
@ -35,14 +35,14 @@ items.size // 5
|
|||||||
|
|
||||||
// 例三
|
// 例三
|
||||||
function divs () {
|
function divs () {
|
||||||
return [...document.querySelectorAll('div')]
|
return [...document.querySelectorAll('div')];
|
||||||
}
|
}
|
||||||
|
|
||||||
var set = new Set(divs())
|
var set = new Set(divs());
|
||||||
set.size // 56
|
set.size // 56
|
||||||
|
|
||||||
// 类似于
|
// 类似于
|
||||||
divs().forEach(div => set.add(div))
|
divs().forEach(div => set.add(div));
|
||||||
set.size // 56
|
set.size // 56
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -73,10 +73,10 @@ set // Set {NaN}
|
|||||||
```javascript
|
```javascript
|
||||||
let set = new Set();
|
let set = new Set();
|
||||||
|
|
||||||
set.add({})
|
set.add({});
|
||||||
set.size // 1
|
set.size // 1
|
||||||
|
|
||||||
set.add({})
|
set.add({});
|
||||||
set.size // 2
|
set.size // 2
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -376,7 +376,7 @@ class Foo {
|
|||||||
}
|
}
|
||||||
method () {
|
method () {
|
||||||
if (!foos.has(this)) {
|
if (!foos.has(this)) {
|
||||||
throw new TypeError('Foo.prototype.method 只能在Foo的实例上调用!')
|
throw new TypeError('Foo.prototype.method 只能在Foo的实例上调用!');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -154,7 +154,7 @@ Symbol类型还可以用于定义一组常量,保证这组常量的值都是
|
|||||||
log.levels = {
|
log.levels = {
|
||||||
DEBUG: Symbol('debug'),
|
DEBUG: Symbol('debug'),
|
||||||
INFO: Symbol('info'),
|
INFO: Symbol('info'),
|
||||||
WARN: Symbol('warn'),
|
WARN: Symbol('warn')
|
||||||
};
|
};
|
||||||
log(log.levels.DEBUG, 'debug message');
|
log(log.levels.DEBUG, 'debug message');
|
||||||
log(log.levels.INFO, 'info message');
|
log(log.levels.INFO, 'info message');
|
||||||
|
Loading…
x
Reference in New Issue
Block a user