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

Merge branch 'gh-pages' of github.com:ruanyf/es6tutorial into gh-pages

This commit is contained in:
ruanyf 2016-05-19 23:25:43 +08:00
commit 1764e48fdf
8 changed files with 107 additions and 107 deletions

View File

@ -14,7 +14,7 @@ function Point(x,y){
Point.prototype.toString = function () {
return '(' + this.x + ', ' + this.y + ')';
}
};
```
上面这种写法跟传统的面向对象语言比如C++和Java差异很大很容易让新学习这门语言的程序员感到困惑。
@ -74,7 +74,7 @@ class Point {
Point.prototype = {
toString(){},
toValue(){}
}
};
```
在类的实例上面调用方法,其实就是调用原型上的方法。
@ -100,7 +100,7 @@ class Point {
Object.assign(Point.prototype, {
toString(){},
toValue(){}
})
});
```
`prototype`对象的`constructor`属性直接指向“类”的本身这与ES5的行为是一致的。
@ -133,11 +133,11 @@ Object.getOwnPropertyNames(Point.prototype)
```javascript
var Point = function (x, y){
// ...
}
};
Point.prototype.toString = function() {
// ...
}
};
Object.keys(Point.prototype)
// ["toString"]
@ -585,7 +585,7 @@ var obj = {
toString() {
return "MyObject: " + super.toString();
}
}
};
obj.toString(); // MyObject: [object Object]
```

View File

@ -94,12 +94,12 @@ import { mixins } from './mixins'
const Foo = {
foo() { console.log('foo') }
}
};
@mixins(Foo)
class MyClass {}
let obj = new MyClass()
let obj = new MyClass();
obj.foo() // 'foo'
```
@ -108,7 +108,7 @@ obj.foo() // 'foo'
```javascript
const Foo = {
foo() { console.log('foo') }
}
};
class MyClass {}
@ -169,7 +169,7 @@ function nonenumerable(target, name, descriptor) {
下面的`@log`修饰器,可以起到输出日志的作用。
```bash
```javascript
class Math {
@log
add(a, b) {
@ -498,7 +498,7 @@ export function mixins(...list) {
然后,就可以使用上面这个修饰器,为类“混入”各种方法。
```javascript
import { mixins } from './mixins'
import { mixins } from './mixins';
const Foo = {
foo() { console.log('foo') }
@ -600,7 +600,7 @@ Trait也是一种修饰器效果与Mixin类似但是提供更多功能
下面采用[traits-decorator](https://github.com/CocktailJS/traits-decorator)这个第三方模块作为例子。这个模块提供的traits修饰器不仅可以接受对象还可以接受ES6类作为参数。
```javascript
import { traits } from 'traits-decorator'
import { traits } from 'traits-decorator';
class TFoo {
foo() { console.log('foo') }
@ -608,12 +608,12 @@ class TFoo {
const TBar = {
bar() { console.log('bar') }
}
};
@traits(TFoo, TBar)
class MyClass { }
let obj = new MyClass()
let obj = new MyClass();
obj.foo() // foo
obj.bar() // bar
```
@ -623,7 +623,7 @@ obj.bar() // bar
Trait不允许“混入”同名方法。
```javascript
import {traits } from 'traits-decorator'
import { traits } from 'traits-decorator';
class TFoo {
foo() { console.log('foo') }
@ -632,7 +632,7 @@ class TFoo {
const TBar = {
bar() { console.log('bar') },
foo() { console.log('foo') }
}
};
@traits(TFoo, TBar)
class MyClass { }
@ -647,7 +647,7 @@ class MyClass { }
一种解决方法是排除TBar的foo方法。
```javascript
import { traits, excludes } from 'traits-decorator'
import { traits, excludes } from 'traits-decorator';
class TFoo {
foo() { console.log('foo') }
@ -656,12 +656,12 @@ class TFoo {
const TBar = {
bar() { console.log('bar') },
foo() { console.log('foo') }
}
};
@traits(TFoo, TBar::excludes('foo'))
class MyClass { }
let obj = new MyClass()
let obj = new MyClass();
obj.foo() // foo
obj.bar() // bar
```
@ -671,7 +671,7 @@ obj.bar() // bar
另一种方法是为TBar的foo方法起一个别名。
```javascript
import { traits, alias } from 'traits-decorator'
import { traits, alias } from 'traits-decorator';
class TFoo {
foo() { console.log('foo') }
@ -680,12 +680,12 @@ class TFoo {
const TBar = {
bar() { console.log('bar') },
foo() { console.log('foo') }
}
};
@traits(TFoo, TBar::alias({foo: 'aliasFoo'}))
class MyClass { }
let obj = new MyClass()
let obj = new MyClass();
obj.foo() // foo
obj.aliasFoo() // foo
obj.bar() // bar

View File

@ -29,15 +29,15 @@ it.next() // { value: "a", done: false }
it.next() // { value: "b", done: false }
it.next() // { value: undefined, done: true }
function makeIterator(array){
function makeIterator(array) {
var nextIndex = 0;
return {
next: function(){
next: function() {
return nextIndex < array.length ?
{value: array[nextIndex++], done: false} :
{value: undefined, done: true};
}
}
};
}
```
@ -52,15 +52,15 @@ function makeIterator(array){
对于遍历器对象来说,`done: false``value: undefined`属性都是可以省略的,因此上面的`makeIterator`函数可以简写成下面的形式。
```javascript
function makeIterator(array){
function makeIterator(array) {
var nextIndex = 0;
return {
next: function(){
next: function() {
return nextIndex < array.length ?
{value: array[nextIndex++]} :
{done: true};
}
}
};
}
```
@ -74,14 +74,14 @@ it.next().value // '1'
it.next().value // '2'
// ...
function idMaker(){
function idMaker() {
var index = 0;
return {
next: function(){
next: function() {
return {value: index++, done: false};
}
}
};
}
```
@ -166,31 +166,31 @@ for (var value of range(0, 3)) {
下面是通过遍历器实现指针结构的例子。
```javascript
function Obj(value){
function Obj(value) {
this.value = value;
this.next = null;
}
Obj.prototype[Symbol.iterator] = function(){
Obj.prototype[Symbol.iterator] = function() {
var iterator = {
next: next
};
var current = this;
function next(){
if (current){
function next() {
if (current) {
var value = current.value;
var done = current.next === null;
current = current.next;
return {
done: done,
value: value
}
};
} else {
return {
done: true
}
};
}
}
return iterator;
@ -204,7 +204,7 @@ one.next = two;
two.next = three;
for (var i of one){
console.log(i)
console.log(i);
}
// 1
// 2

View File

@ -91,7 +91,7 @@ export {firstName, lastName, year};
export命令除了输出变量还可以输出函数或类class
```javascript
export function multiply (x, y) {
export function multiply(x, y) {
return x * y;
};
```
@ -350,7 +350,7 @@ import {crc32} from 'crc32';
// modules.js
function add(x, y) {
return x * y;
};
}
export {add as default};
// 等同于
// export default add;
@ -402,7 +402,7 @@ export default 42;
export default class { ... }
// main.js
import MyClass from 'MyClass'
import MyClass from 'MyClass';
let o = new MyClass();
```
@ -499,7 +499,7 @@ $ node main.js
4
```
ES6模块的运行机制与CommonJS不一样它遇到模块加载命令`import`不会去执行模块而是只生成一个动态的只读引用。等到真的需要用到时再到模块里面去取值换句话说ES6的输入有点像Unix系统的”符号连接“,原始值变了,`import`输入的值也会跟着变。因此ES6模块是动态引用并且不会缓存值模块里面的变量绑定其所在的模块。
ES6模块的运行机制与CommonJS不一样它遇到模块加载命令`import`不会去执行模块而是只生成一个动态的只读引用。等到真的需要用到时再到模块里面去取值换句话说ES6的输入有点像Unix系统的“符号连接”,原始值变了,`import`输入的值也会跟着变。因此ES6模块是动态引用并且不会缓存值模块里面的变量绑定其所在的模块。
还是举上面的例子。
@ -545,7 +545,7 @@ baz
上面代码表明ES6模块不会缓存运行结果而是动态地去被加载的模块取值并且变量总是绑定其所在的模块。
由于ES6输入的模块变量只是一个”符号连接“,所以这个变量是只读的,对它进行重新赋值会报错。
由于ES6输入的模块变量只是一个“符号连接”,所以这个变量是只读的,对它进行重新赋值会报错。
```javascript
// lib.js
@ -571,7 +571,7 @@ function C() {
};
this.show = function () {
console.log(this.sum);
}
};
}
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处理“循环加载”的方法是不一样的返回的结果也不一样。

View File

@ -146,7 +146,7 @@ var obj = {
* m(){
yield 'hello world';
}
}
};
```
## 属性名表达式
@ -233,9 +233,9 @@ var person = {
console.log(this.name);
},
get firstName() {
return "Nicholas"
return "Nicholas";
}
}
};
person.sayName.name // "sayName"
person.firstName.name // "get firstName"
@ -633,12 +633,12 @@ Reflect.ownKeys({ [Symbol()]:0, b:0, 10:0, 2:0, a:0 })
// es6的写法
var obj = {
method: function() { ... }
}
};
obj.__proto__ = someOtherObj;
// es5的写法
var obj = Object.create(someOtherObj);
obj.method = function() { ... }
obj.method = function() { ... };
```
该属性没有写入ES6的正文而是写入了附录原因是`__proto__`前后的双下划线说明它本质上是一个内部属性而不是一个正式的对外的API只是由于浏览器广泛支持才被加入了ES6。标准明确规定只有浏览器必须部署这个属性其他运行环境不一定需要部署而且新的代码最好认为这个属性是不存在的。因此无论从语义的角度还是从兼容性的角度都不要使用这个属性而是使用下面的`Object.setPrototypeOf()`(写操作)、`Object.getPrototypeOf()`(读操作)、`Object.create()`(生成操作)代替。
@ -662,7 +662,7 @@ Object.defineProperty(Object.prototype, '__proto__', {
return undefined;
}
let status = Reflect.setPrototypeOf(this, proto);
if (! status) {
if (!status) {
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`
```javascript
let {keys, values, entries} = Object;
let {keys, values, entries} = Object;
let obj = { a: 1, b: 2, c: 3 };
for (let key of keys(obj)) {
@ -943,9 +943,9 @@ var o = Object.create({ x: 1, y: 2 });
o.z = 3;
let { x, ...{ y, z } } = o;
x; // 1
y; // undefined
z; // 3
x // 1
y // undefined
z // 3
```
上面代码中,变量`x`是单纯的解构赋值所以可以读取继承的属性Rest解构赋值产生的变量`y``z`,只能读取对象自身的属性,所以只有变量`z`可以赋值成功。
@ -1010,7 +1010,7 @@ let aWithOverrides = Object.assign({}, a, { x: 1, y: 2 });
```javascript
let newVersion = {
...previousVersion,
name: 'New Name', // Override the name property
name: 'New Name' // Override the name property
};
```
@ -1074,7 +1074,7 @@ ES7有一个提案提出了`Object.getOwnPropertyDescriptors`方法,返回
```javascript
const obj = {
foo: 123,
get bar() { return 'abc' },
get bar() { return 'abc' }
};
Object.getOwnPropertyDescriptors(obj)

View File

@ -35,7 +35,7 @@ obj.count = 1
ES6原生提供Proxy构造函数用来生成Proxy实例。
```javascript
var proxy = new Proxy(target, handler)
var proxy = new Proxy(target, handler);
```
Proxy对象的所有用法都是上面这种形式不同的只是`handler`参数的写法。其中,`new Proxy()`表示生成一个Proxy实例target参数表示所要拦截的目标对象`handler`参数也是一个对象,用来定制拦截行为。
@ -73,7 +73,7 @@ target.a // "b"
一个技巧是将Proxy对象设置到`object.proxy`属性,从而可以在`object`对象上调用。
```javascript
var object = { proxy: new Proxy(target, handler) }
var object = { proxy: new Proxy(target, handler) };
```
Proxy实例也可以作为其他对象的原型对象。
@ -97,15 +97,15 @@ obj.time // 35
var handler = {
get: function(target, name) {
if (name === 'prototype') return Object.prototype;
return 'Hello, '+ name;
return 'Hello, ' + name;
},
apply: function(target, thisBinding, args) { return args[0]; },
construct: function(target, args) { return args[1]; }
};
var fproxy = new Proxy(function(x,y) {
return x+y;
}, handler);
var fproxy = new Proxy(function(x, y) {
return x + y;
}, handler);
fproxy(1,2); // 1
new fproxy(1,2); // 2
@ -279,19 +279,6 @@ pipe(3).double.pow.reverseInt.get; // 63
下面的例子则是利用`get`拦截实现一个生成各种DOM节点的通用函数`dom`
```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({}, {
get(target, property) {
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()
@ -357,7 +357,7 @@ var handler = {
invariant(key, 'set');
return true;
}
}
};
function invariant (key, action) {
if (key[0] === '_') {
throw new Error(`Invalid attempt to ${action} private "${key}" property`);
@ -382,7 +382,7 @@ var handler = {
apply (target, ctx, args) {
return Reflect.apply(...arguments);
}
}
};
```
`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`拦截就会报错。
@ -475,7 +475,7 @@ var handler = {
construct (target, args) {
return new target(...args);
}
}
};
```
下面是一个例子。
@ -515,15 +515,15 @@ var handler = {
invariant(key, 'delete');
return true;
}
}
};
function invariant (key, action) {
if (key[0] === '_') {
throw new Error(`Invalid attempt to ${action} private "${key}" property`);
}
}
var target = { _prop: 'foo' }
var proxy = new Proxy(target, handler)
var target = { _prop: 'foo' };
var proxy = new Proxy(target, handler);
delete proxy._prop
// Error: Invalid attempt to delete private "_prop" property
```
@ -537,11 +537,11 @@ delete proxy._prop
```javascript
var handler = {
defineProperty (target, key, descriptor) {
return false
return false;
}
}
var target = {}
var proxy = new Proxy(target, handler)
};
var target = {};
var proxy = new Proxy(target, handler);
proxy.foo = 'bar'
// TypeError: proxy defineProperty handler returned false for property '"foo"'
```
@ -557,9 +557,9 @@ var handler = {
enumerate (target) {
return Object.keys(target).filter(key => key[0] !== '_')[Symbol.iterator]();
}
}
var target = { prop: 'foo', _bar: 'baz', _prop: 'foo' }
var proxy = new Proxy(target, handler)
};
var target = { prop: 'foo', _bar: 'baz', _prop: 'foo' };
var proxy = new Proxy(target, handler);
for (let key in proxy) {
console.log(key);
// "prop"
@ -607,11 +607,11 @@ for (var x in p) {} // 报错
var handler = {
getOwnPropertyDescriptor (target, key) {
if (key[0] === '_') {
return
return;
}
return Object.getOwnPropertyDescriptor(target, key)
return Object.getOwnPropertyDescriptor(target, key);
}
}
};
var target = { _foo: 'bar', baz: 'tar' };
var proxy = new Proxy(target, handler);
Object.getOwnPropertyDescriptor(proxy, 'wat')
@ -682,7 +682,7 @@ var p = new Proxy({}, {
}
});
Object.isExtensible(p); // 报错
Object.isExtensible(p) // 报错
```
### ownKeys()
@ -732,7 +732,7 @@ for (let key of Object.keys(proxy)) {
`preventExtensions`方法拦截`Object.preventExtensions()`。该方法必须返回一个布尔值。
这个方法有一个限制,只有当`Object.isExtensible(proxy)``false`(即不可扩展)时,`proxy.preventExtensions`才能返回true否则会报错。
这个方法有一个限制,只有当`Object.isExtensible(proxy)``false`(即不可扩展)时,`proxy.preventExtensions`才能返回`true`,否则会报错。
```javascript
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`,因此报错。
@ -773,7 +773,7 @@ var handler = {
setPrototypeOf (target, proto) {
throw new Error('Changing the prototype is forbidden');
}
}
};
var proto = {};
var target = function () {};
var proxy = new Proxy(target, handler);
@ -915,7 +915,7 @@ Reflect.apply(Math.floor, undefined, [1.75]) // 1
var obj = {
get foo() { return this.bar(); },
bar: function() { ... }
}
};
// 下面语句会让 this.bar()
// 变成调用 wrapper.bar()

View File

@ -11,7 +11,7 @@ Set本身是一个构造函数用来生成Set数据结构。
```javascript
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) {
console.log(i);
@ -25,7 +25,7 @@ Set函数可以接受一个数组或类似数组的对象作为参数
```javascript
// 例一
var set = new Set([1, 2, 3, 4, 4])
var set = new Set([1, 2, 3, 4, 4]);
[...set]
// [1, 2, 3, 4]
@ -35,14 +35,14 @@ items.size // 5
// 例三
function divs () {
return [...document.querySelectorAll('div')]
return [...document.querySelectorAll('div')];
}
var set = new Set(divs())
var set = new Set(divs());
set.size // 56
// 类似于
divs().forEach(div => set.add(div))
divs().forEach(div => set.add(div));
set.size // 56
```
@ -73,10 +73,10 @@ set // Set {NaN}
```javascript
let set = new Set();
set.add({})
set.add({});
set.size // 1
set.add({})
set.add({});
set.size // 2
```
@ -376,7 +376,7 @@ class Foo {
}
method () {
if (!foos.has(this)) {
throw new TypeError('Foo.prototype.method 只能在Foo的实例上调用')
throw new TypeError('Foo.prototype.method 只能在Foo的实例上调用');
}
}
}

View File

@ -154,7 +154,7 @@ Symbol类型还可以用于定义一组常量保证这组常量的值都是
log.levels = {
DEBUG: Symbol('debug'),
INFO: Symbol('info'),
WARN: Symbol('warn'),
WARN: Symbol('warn')
};
log(log.levels.DEBUG, 'debug message');
log(log.levels.INFO, 'info message');