原文地址
用法类似 var
。
(() => {
for (var i = 0; i < 6; i++) {}
console.log(i); // 6
})();
(() => {
for (let i = 0; i < 6; i++) {}
console.log(i); // ReferenceError: i is not defined
})();
(() => {
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
}
}
a[6](); // 10
})();
(() => {
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
}
}
a[6](); // 6
})();
(() => {
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
}
}
a[6](); // 10
})();
(() => {
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
}
}
a[6](); // 6
})();
// let 声明之前使用会报错
(() => {
if (true) {
typeof undefined_save; // 不报错
typeof save; // ReferenceError: save is not defined
let save;
}
})();
(() => {
let save = 7;
let save = 6; // SyntaxError: Identifier 'save' has already been declared
var you = 7;
var you = 6; // OK
})();
(() => {
/**
* 数组
*/
let [a,b,c] = [1, 3, 4];
console.log(a); // 1
console.log(b); // 3
console.log(c); // 4
/**
* 数组中数组
*/
let [v1, [[v2], v3]] = [1, [[2], 6]];
console.log(v1); // 1
console.log(v2); // 2
console.log(v3); // 6
/**
* 解析不到
*/
let [v4] = [];
let [v5, v6] = [6];
console.log(v4); // undefined
console.log(v5); // 6
console.log(v6); // undefined
})();
(() => {
/**
* 默认值
*/
let [v1 = true] = [];
let [v2, v3 = 'b'] = ['a'];
let [v4, v5 = 'b'] = ['a', undefined];
console.log(v1); // true
console.log(v2); // a
console.log(v3); // b
console.log(v4); // a
console.log(v5); // b
/**
* null 生效
* undefined 不生效
*/
let [v6 = 'save'] = [undefined];
let [v7 = 26] = [null];
console.log(v6); // save
console.log(v7); // null
})();
普通对象
(() => {
let object = {
array: [
'Save',
{
you: 'you from anything'
}
]
};
let {array: [save, {you}]} = object;
console.log(save); // Save
console.log(you); // you from anything
})();
嵌套对象
(() => {
(() => {
let object = {};
let array = [];
({save: object.save, you: array[7]} = {save: 'Save', you: 'you'});
console.log(object.save); // Save
console.log(array[7]); // you from anything
})();
系统类对象
(() => {
/**
* Math
*/
let {log: mathLog, sin: mathSin, cos: mathCos} = Math;
console.log(mathLog);
console.log(mathSin);
console.log(mathCos);
/**
* Array
*/
let array = ["Save", "you", "from", "anything"];
let {length: count, 0: firstElement, [array.length - 1]: lastElement} = array;
console.log(count); // 4
console.log(firstElement); // Save
console.log(lastElement); // anything
/**
* String
*/
const [s,a,v,e] = "Save";
console.log(s); // S
console.log(a); // a
console.log(v); // v
console.log(v); // e
})();
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模板编译title>
head>
<body>
<div id="div">div>
<script>
let template = `
<% for(var i=0; i < data.supplies.length; i++) { %>
<li><%= data.supplies[i] %>li>
<% } %>
ul>
`;
function compile(template) {
let evalExpr = /<%=(.+?)%>/g;
let expr = /<%([\s\S]+?)%>/g;
template = template
.replace(evalExpr, '`); \n echo( $1 ); \n echo(`')
.replace(expr, '`); \n $1 \n echo(`');
template = 'echo(`' + template + '`);';
let script =
`(function parse(data){
var output = "";
function echo(html){
output += html;
}
${ template }
return output;
})`;
return script;
}
let div = document.getElementById("div");
let parse = eval(compile(template));
div.innerHTML = parse({supplies: ["CaMnter", "Save you from anything", "魔法使"]});
script>
body>
html>
Number.isNaN(...)
: 判断一个值是否为 NaN
。
(() => {
/**
* ES6
*/
console.log(Number.isNaN(NaN)); // true
/**
* ES5
*/
(function (global) {
var global_isNaN = global.isNaN;
Object.defineProperty(Number, 'isNaN', {
value: function isNaN(value) {
return typeof value === 'number' && global_isNaN(value);
},
configurable: true,
enumerable: false,
writable: true
});
})(this);
console.log(Number.isNaN(NaN)); // true
})();
Number.isSafeInteger(...)
: 来判断一个整数是否落在 -2^53 ~ 2^53 之内。
JavaScript 能够准确表示的整数范围在 -2^53 ~ 2^53 之间(不含两个端点),超过这个范围,无法精确表示这个值。
(() => {
/**
* ES6
*/
console.log(Number.isSafeInteger(9007199254740990)); // true
console.log(Number.isSafeInteger(9007199254740992)); // false
/**
* ES5
*/
Number.isSafeInteger = function (n) {
return (typeof n === 'number' &&
Math.round(n) === n &&
Number.MIN_SAFE_INTEGER <= n &&
n <= Number.MAX_SAFE_INTEGER);
}
console.log(Number.isSafeInteger(9007199254740990)); // true
console.log(Number.isSafeInteger(9007199254740992)); // false
})();
Array.of(...)
: 方法用于将一组值,转换为数组。
(() => {
// ES6
console.log(Array.of()); // []
console.log(Array.of(undefined)); // [ undefined ]
console.log(Array.of(7)); // [ 7 ]
console.log(Array.of(6, 7)); // [ 6, 7 ]
// ES5 部署 Array.Of()
function ArrayOf() {
return [].slice.call(arguments);
}
console.log(Array.of(7)); // [ 7 ]
})();
Array.prototype.includes
: 方法返回一个布尔值,表示某个数组是否包含给定的值。
(() => {
// 属于 ES7 语法
// ES6 部署 includes
const arrayIncludes = (() => Array.prototype.includes ?
(array, value) => array.includes(value) :
(array, value) => array.some(el => el === value))();
console.log(arrayIncludes(['Save', 'you', 'from', 'anything'], 'Save')); // true
})();
(() => {
const SAVE = "Save";
/**
* ES6
*/
function es6function(value = SAVE) {
console.log(value);
}
es6function(); // Save
/**
* ES5
*/
function es5function(value) {
if (typeof value === 'undefined') {
value = SAVE;
}
console.log(value);
}
es5function(); // Save
})();
(() => {
const SAVE = "Save";
function func({index, sign = SAVE}) {
console.log(index, sign);
}
func({index: 67, sign: 'you'}); // 67 'you'
func({index: 67}); // 67 'Save'
func({}); // undefined 'Save'
})();
(() => {
/**
* 参数可省
*/
function funcA(v = undefined) {
return v;
}
funcA();
/**
* 参数不可省
*/
function throwIfMissing() {
throw new Error('Missing parameter');
}
function funcB(v = throwIfMissing()) {
return v;
}
funcB(); // Error: Missing parameter
})();
rest 参数:...变量名
,代表一个数组 。
(() => {
function func(array, ...items) {
items.forEach(function (item) {
array.push(item);
});
}
let array = [];
func(array, 2, 6, 7);
console.log(array); // [ 2, 6, 7 ]
})();
扩展运算符:...数组
,解数组。将数组转为用逗号分隔的参数序列。
(() => {
function func(v, w, x, y, z) {
return v + w + x + y + z;
}
let args = [2, 3, 3];
console.log(func(-1, ...args, 2, ...[6, 7])); // 9
})();
(() => {
let insertFunction = target => ({
into: array => ({
after: value => {
array.splice(array.indexOf(value) + 1, 0, target);
return array;
}
})
});
console.log(insertFunction(6).into([2, 7]).after(2)); // [ 2, 6, 7 ]
})();
(() => {
let save = "Save";
let object = {save}; // 等于 let object = {save: save};
console.log(object.save); // Save
function func(x, y) {
// 等于 return {x: x, y: y};
return {x, y};
}
console.log(func('CaMnter', '2233').x); // CaMnter
})();
方法简写 更像 Java 的方法声明。
(() => {
let object = {
method(value){ // 等于 method: function (value)
return value;
}
}
console.log(object.method('Save')); // Save
})();
Symbol
保证每个属性的名字都是独一无二,从根本上防止属性名的冲突。
这就是 ES6 引入 Symbol
的原因。
ES6 引入了一种新的原始数据类型 Symbol
。
JavaScript 语言的第七种数据类型。
前六种是:Undefined、Null、Boolean、String、Number、对象Object。
ES6 以后, 对象的属性名现在可以有两种类型. 一种是 String
, 一种是 Symbol
。
凡是属性名属于 Symbol
类型, 就都是独一无二的, 可以保证不会与其他属性名产生冲突。
(() => {
let symbol = Symbol('Save');
let object = {
toString(){
return 'object-toString';
}
}
console.log(symbol); // Symbol(Save)
console.log(typeof symbol); // symbol
console.log(Symbol(object)); // Symbol(object-toString)
console.log(Symbol() === Symbol()); // true
})();
ES6 原生提供 Proxy
构造函数:
let proxy = new Proxy(target, handler);
target
参数表示所要拦截的目标对象。
handler
参数也是一个对象,用来定制拦截行为。
注意: 要使得 Proxy
起作用,必须针对 Proxy
实例进行操作,而不是针对 目标对象 进行操作。
Proxy
实际上 重载 了 点运算符。
即用自己的定义覆盖了语言的原始定义。
Proxy
能代理的方法,在 Reflect
都可以找得到。
(() => {
function createSmartArray(...elements) {
let minusIndexArrayHandler = {
get(target, propertyKey, receiver) {
let index = Number(propertyKey);
return Reflect.get(
target,
index < 0 ?
String(index + target.length) :
propertyKey,
receiver);
}
};
let target = [];
target.push(...elements);
return new Proxy(target, minusIndexArrayHandler);
}
let array = createSmartArray(0, 1, 2, 3, 4, 5);
console.log(array[-1]); // 5
console.log(array[-2]); // 4
})();
(() => {
let double = n => n * 2;
let pow = n => n * n;
let reverseInt = n => n.toString().split("").reverse().join("") | 0;
let pipeMap = new Map();
pipeMap.set(double.name, double);
pipeMap.set(pow.name, pow);
pipeMap.set(reverseInt.name, reverseInt);
let pipe = (function () {
return function (value) {
let funcStack = [];
let proxy = new Proxy({}, {
get: function (target, propertyKey, receiver) {
if (propertyKey === 'get') {
return funcStack.reduce(function (previousFunction, currentFunction) {
return currentFunction(previousFunction);
}, value);
}
funcStack.push(pipeMap.get(propertyKey));
return proxy;
}
});
return proxy;
}
}());
console.log(pipe(3).double.pow.reverseInt.get); // 63
})();
(() => {
let validator = {
set(target, propertyKey, value, receiver) {
if (propertyKey === 'save' &&
value == null) {
throw new TypeError('The save is not null');
} else {
return Reflect.set(target, propertyKey, value, receiver);
}
}
}
let camnter = new Proxy({}, validator);
camnter.save = 'save';
console.log(camnter.save); // save
camnter.save = null; // TypeError: The save is not null
})();
(() => {
let handler = {
get(target, propertyKey, receiver) {
this.invariant(propertyKey, 'get');
return Reflect.get(target, propertyKey, receiver);
},
set(target, propertyKey, value, receiver) {
this.invariant(propertyKey, 'set');
Reflect.set(target, propertyKey, value, receiver);
},
invariant (key, action) {
if (key[0] === '_') {
throw new Error(`Invalid attempt to ${action} private "${key}" property`);
}
}
};
let proxy = new Proxy({
_save: 'Save you from anything'
}, handler);
proxy._save; // Error: Invalid attempt to get private "_save" property
proxy._save = '2233'; // Error: Invalid attempt to set private "_save" property
})();
(() => {
function sum(left, right) {
return left + right;
}
let proxy = new Proxy(sum, {
apply(target, thisArgument, argumentsList){
return Reflect.apply(...arguments) * 2;
}
})
console.log(proxy(22, 33)); // 110
console.log(proxy.call(null, 22, 33)); // 110
console.log(proxy.apply(null, [22, 33])); // 110
// 调用 Reflect.apply 方法,也会被拦截
console.log(Reflect.apply(proxy, null, [22, 33])); // 110
})();
(() => {
let target = {_save: 'save', save: 'save'};
let proxy = new Proxy(target, {
has(target, propertyKey){
if (propertyKey[0] === '_')
return false;
return Reflect.has(target, propertyKey);
}
});
console.log('_save' in proxy); // true
})();
(() => {
let object = {save: 'save'};
Object.preventExtensions(object); // 设置对象不可扩展
let proxy = new Proxy(object, {
has(target, propertyKey){
return false;
}
});
console.log('save' in proxy); // TypeError: 'has' on proxy: trap returned falsish for property 'save' but the proxy target is not extensible
})();
(() => {
let target = {_save: 'save'};
let proxy = new Proxy(target, {
deleteProperty(target, propertyKey){
this.invariant(propertyKey, 'delete');
Reflect.deleteProperty(target, propertyKey);
},
invariant(propertyKey, action){
if (propertyKey[0] === '_') {
throw new Error(`Invalid attempt to ${action} private "${propertyKey}" property`);
}
}
})
delete proxy._save; // Error: Invalid attempt to delete private "_save" property
})();
(() => {
let target = {
save: 'save',
_save: '_save'
};
let proxy = new Proxy(target, {
ownKeys(target){
return Reflect.ownKeys(target).filter(key => key[0] !== '_');
}
});
console.log(Object.keys(proxy)); // [ 'save' ]
})();
(() => {
let target = {};
let {proxy, revoke} = Proxy.revocable(target, {});
proxy.save = '_save';
console.log(proxy.save); // _save
revoke();
proxy.save; // TypeError: Cannot perform 'get' on a proxy that has been revoked
})();
Proxy
可以代理针对目标对象的访问,但它不是目标对象的透明代理。
在不做任何拦截的情况下,也无法保证与目标对象的行为一致。
主要原因:
Proxy
代理的情况下,目标对象内部的 this
关键字会指向 Proxy
代理。
(() => {
let target = {
compareThis: function () {
return this === proxy;
}
};
let proxy = new Proxy(target, {});
console.log(target.compareThis()); // false
console.log(proxy.compareThis()); // true
})();
this
指向的变化,导致 Proxy
无法代理目标对象。
(() => {
let personMap = new WeakMap();
class Person {
constructor(name) {
personMap.set(this, name);
}
get name() {
let name = personMap.get(this);
console.log(name);
return name;
}
}
let you = new Person('you');
you.name; // you
let youProxy = new Proxy(you, {});
/*
* youProxy.name 访问时
* this 指向 youProxy
* 导致无法取到值,所以返回 undefined
*/
youProxy.name; // undefined
})();
有些原生对象的内部属性,只有通过正确的 this
才能拿到。
Proxy
也无法代理这些原生对象的属性。
解决办法: this
绑定原对象。
(() => {
let date = new Date('2017-02-07');
let proxy = new Proxy(date, {});
proxy.getDate(); // TypeError: this is not a Date object.
let getDateHandler = {
get(target, propertyKey, receiver){
if (propertyKey === 'getDate') {
return target.getDate.bind(target);
}
return Reflect.get(target, propertyKey, receiver);
}
}
let smartProxy = new Proxy(date, getDateHandler);
console.log(smartProxy.getDate()); // 7
})();
Promise
是异步编程的一种方案,用于替代原本的 “回调和事件” 模式。
Promise
的概念最早由社区提出来的,后来 ES6 统一用户,原生提供了 Promise
。
Promise
是一个对象,可以获取异步操作的消息。各种异步操作可以用同样的方法进行处理。
特点:
Promise
对象的状态不受外界影响。Promise
代表一个异步操作,有三种状态:Pending:进行中、Resoled:已完成、Rejected:已失败。 Promise
可以将异步操作以同步操作的形式表达出来,避免了层层嵌套的回调,统一的接口,使得控制异步操作更容易。
Promise
的缺点:
Promise
,创建就立即执行,无法中途取消。 Promise
内部抛出错误,也不会反应到外部。 Promise
的构造方法接收一个 方法。
这个方法 有两个参数,这两个参数也是 方法,分别是 resolve
和 reject
。
是由 JavaScript 引擎提供。
resolve
方法的作用:将 Promise
对象的状态从 Pending >> Resolved
将异步操作成功的结果,作为参数传递
reject
方法的作用:将 Promise
对象的状态从 Pending >> Reject
将异步操作失败的错误,作为参数传递
(() => {
let promiseA = new Promise((resolve, reject) => {
resolve(200); // 异步成功
});
let promiseB = new Promise((resolve, reject) => {
reject(400); // 异步失败
});
})();
(() => {
function loadImageAsync(url) {
return new Promise((resolve, reject) => {
let image = new Image();
image.onload = function () {
resolve(image);
};
image.onerror = function () {
reject(new Error('Could not load image at: ' + url));
};
image.src = url;
});
};
})();
(() => {
let getJSON = function (url) {
return new Promise((resolve, reject) => {
function handler() {
if (this.readyState !== 4) {
return;
} else if (this.status == 200) {
resolve(this.response);
} else {
reject(new Error(this.statusText));
}
};
let client = new XMLHttpRequest();
client.open('GET', url);
client.onreadystatechange = handler;
client.responseType = 'json';
client.setRequestHeader('Accept', 'application/json');
client.send();
});
};
getJSON("https://www.camnter.com")
.then(json => {
// success
}, error => {
// failure
});
})();
(() => {
let promiseA = new Promise((resolve, reject) => {
setTimeout(() => reject(new Error('fail')), 2000);
});
let promiseB = new Promise((resolve, reject) => {
setTimeout(() => resolve(promiseA), 1000); // resolve Promise 后,自身的状态无效了
});
promiseB
.then(promise => {
console.log(promise); // Error: fail
})
.catch(error => {
console.log(error);
})
})();
Promise
的 then
方法定义在 原型对象 Promise.prototype 上的。
它的作用是:为 Promise
实例添加状态改变时的回调方法。
第一个参数是 Resolved
状态的回调方法。
第二个参数是 Rejected
状态的回调方法。
/**
* then 进行数据转换
*/
(() => {
new Promise((resolve, reject) => {
resolve(67);
}).then(value => {
return 'Save you from anything ' + value;
}).then(string => {
console.log(string); // Save you from anything 67
});
})();
如果 then
返回了 Promise
,这个 then
后面的 then
都会等待这个 Promise
的状态发生变化后,才会调用。
(() => {
new Promise((resolve, reject) => {
resolve(true);
}).then(call => {
if (!call)return null;
return new Promise((resolve, reject) => {
setTimeout(() => reject(new Error('异空间错误 404 ')), 677);
});
}).then(value => {
console.log(value);
}, error => {
console.log(error); // Error: 异空间错误 404
});
})();
实际上: Promise.prototype.catch == .then(null, rejection)
。
(() => {
new Promise((resolve, reject) => {
reject(new Error('异空间错误 404'));
}).then(value => {
}).then(null, error => {
console.log(error); // Error: 异空间错误 404
})
// 等同于
new Promise((resolve, reject) => {
reject(new Error('异空间错误 404'));
}).then(value => {
}).catch(error => {
console.log(error); // Error: 异空间错误 404
});
})();
/**
* reject 等同于 抛出错误
*/
(() => {
new Promise((resolve, reject) => {
reject(new Error('异空间错误 404'));
}).catch(error => {
console.log(error); // Error: 异空间错误 404
});
// 等同于
new Promise((resolve, reject) => {
try {
throw new Error(new Error('异空间错误 404'));
} catch (e) {
reject(e);
}
}).catch(error => {
console.log(error); // Error: 异空间错误 404
});
})();
Promise
对象的错误具有 “冒泡” 性质,全部 then
的错误,都由下个 catch
处理,会一直传递下去。
(() => {
new Promise((resolve, reject) => {
resolve('save');
}).then(value => {
}).then(value => {
throw new Error('异空间错误 404');
}).catch(error => {
console.log(error); // Error: 异空间错误 404
});
})();
Promise
体内抛错,不会抛出到体外,更不会报错。
(() => {
// 体内抛错,不进行 Promise catch
new Promise((resolve, reject) => {
throw new Error('异空间错误 404');
});
// 体外抛错
// 由于 Promise 是立即执行的
// 所以,延时 677 后的抛错,Promise 已经执行完了,属于体外抛错
new Promise((resolve, reject) => {
resolve('save');
setTimeout(() => {
try {
throw new Error('异空间错误 404');
} catch (e) {
console.log(e); // Error: 异空间错误 404
}
}, 677);
});
})();
Promise.all
方法用于将多个 Promise
实例,包装成一个新的 Promise
实例。
Promise.all
方法接收一个 数组 作为参数,数组的元素都是 Promise
对象。
不是的话,需要先转为 Promise
对象。
只要数组内 Promise
的状态全部都为 resolve。
Promise.all
得到的 Promise
才会是 resolve。
只要数组内的 Promise
的其中一个状态为 reject。
Promise.all
得到的 Promise
就会是 reject。
(() => {
function getRequestById(id) {
const BASE_URL = 'https://www.camnter.com/topic/'
return new Promise((resolve, reject) => {
if (typeof id === 'number' && Number(id) > 0) {
resolve(BASE_URL + id);
} else {
reject(new Error('Id is not legal'));
}
});
};
function getResponseByRequest(request) {
return new Promise((resolve, reject) => {
if (null !== request && '' !== request) {
resolve(400); // 假如成功了
} else {
reject(new Error('Request is not legal'));
}
});
};
let arrayA = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
Promise.all(arrayA.map(element => {
return getRequestById(element);
})).then(requestArray => {
console.log(requestArray); // [ 'https://www.camnter.com/topic/1', ..., ... ]
return Promise.all(requestArray.map(request => {
return getResponseByRequest(request);
}));
}).then(responseCodeArray => {
console.log(responseCodeArray); // [ 400, ..., ... ]
}).catch(error => {
console.log(error);
});
let arrayB = [-1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; // 假如有一个 id 不合法( -1 )
Promise.all(arrayB.map(element => {
return getRequestById(element);
})).then(requestArray => {
console.log(requestArray);
return Promise.all(requestArray.map(request => {
return getResponseByRequest(request);
}));
}).then(responseCodeArray => {
console.log(responseCodeArray);
}).catch(error => {
console.log(error); // Error: Id is not legal
})
})();
Promise.race
方法也是用于将多个 Promise
实例,包装成一个新的 Promise
实例。
与 Promise.all
的区别在于:只要 Promise
数组中,有一个 Promise
最先改变状态,那么 Promise.race
返回的 Promise
实例。
/**
* 实例:网络请求超时
*/
(() => {
function getResponse() {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(), 2000); // 假如网络请求需要 2000ms 才返回
});
};
Promise.race(
[
getResponse(),
new Promise((resolve, reject) => {
setTimeout(() => reject(new Error('异空间超时')), 1677); // 1677ms 就超时
})
]
).then(value => {
console.log(value);
}).catch(error => {
console.log(error); // Error: 异空间超时
});
})();
Promise.resolve
可以 将现有的对象,转换为 Promise 对象。
Promise.resolve
也是一个简版的 Promise
。
Promise
实例,那么 Promise.resolve
将不做任何修改、原封不动地返回这个实例。
(() => {
const SAVE = 'save';
Promise
.resolve(SAVE)
.then(value => {
console.log(value); // save
});
// 等价于
new Promise((resolve, reject) => {
resolve();
}).then(value => {
});
})();
Promise.resolve
的参数是一个 thenable 对象。
thenable 对象指的是具有 then
方法的对象。
Promise.resolve
方法会将 thenable 对象转为 Promise
对象。
然后就立即执行 thenable 对象的 then
方法。
(() => {
const SAVE = 'save';
let thenable = {
then(resolve, reject) {
resolve(SAVE);
}
};
Promise
.resolve(thenable)
.then(value => {
console.log(value); // save
});
})();
/**
* 参数不是具有 then 方法的对象
*
* Promise.resolve 方法会返回一个新的 Promise 对象,状态设置为 resolved
*/
(() => {
Promise
.resolve('save')
.then(value => {
console.log(value); // save
})
})();
(() => {
setTimeout(function () { // setTimeout(fn, 0) 在 下一轮 "事件循环" 开始时执行
console.log("C");
}, 0);
Promise // Promise.resolve() 在本轮 "事件循环" 结束时执行
.resolve()
.then(() => {
console.log("B");
}).catch(error => {
});
console.log("A"); // console 立即执行,最先输出
// A
// B
// C
})();
Promise.reject
可以 将现有的对象,转换为 rejected 状态的 Promise
对象。
(() => {
const ERROR_MSG = '异空间错误 404';
Promise
.reject(ERROR_MSG)
.catch(error => {
console.log(error); // 异空间错误 404
});
// 等价于
new Promise((resolve, reject) => {
reject(ERROR_MSG);
}).catch(error => {
console.log(error); // 异空间错误 404
});
})();
Promise.reject
的参数是一个 thenable 对象。
那么在 catch
方法中捕获的就是 thenable 对象,不是 reject 传下来的数据。
(() => {
const ERROR_MSG = '异空间错误 404';
const thenable = {
then(resolve, reject) {
reject(ERROR_MSG);
}
};
Promise
.reject(thenable)
.catch(error => {
console.log(error === thenable); // true
});
})();
Promise
的结尾 then
或者 catch
。如果继续抛出异常的话,是不会被捕获到的,因为 Promise
的异常不会抛出到外部。
需要一个方法在回调链的尾端,保证抛出任何可能出现的错误,利用 setTimeout
抛出一个全局错误。
/**
* done 源码
*/
Promise.prototype.done = function (resolve, reject) {
return this
.then(resolve, reject)
.catch(error => {
setTimeout(() => {
throw error;
}, 0);
});
};
/**
* done 使用
*/
(() => {
Promise
.resolve('Save')
.then(value => {
return value + " you from anything";
})
.then(value => {
throw new Error('异空间错误 404'); // 异空间错误 404
})
.done();
})();
不管是 resolve,还是 reject,都会执行的方法。
原理是拿到 Promise
,添加一次 then
。
resolve 的 时候 resolve + then。
reject 的 时候 resolve + then。
总之就是: 强行 resolve + then。
/**
* finally 源码
*/
Promise.prototype.finally = function (callback) {
let constructor = this.constructor;
return this.then(value => {
constructor.resolve(callback()).then(() => value);
}, error => {
constructor.resolve(callback()).then(() => {
throw error
});
})
};
(() => {
Promise
.resolve('Save')
.then(value => {
return value + " you from anything";
})
.then(value => {
throw new Error('异空间错误 404');
})
.done()
.finally(() => {
console.log("[promise # finally]"); // [promise # finally]
});
})();
(() => {
const preloadImagePromise = function (path) {
return new Promise((resolve, reject) => {
let image = new Image();
image.onload = resolve;
image.error = reject;
image.src = path;
});
};
})();
/**
* 当 Generator 遇到异步操作的时候,都会返回一个 Promise 对象
*/
(() => {
function getSave() {
return Promise.resolve('Save');
};
let generator = function*() {
try {
let save = yield getSave();
console.log(save);
} catch (e) {
console.log(e);
}
};
function run(generator) {
let iterator = generator();
function start(result) {
if (result.done)return result.value;
return result.value.then(value => {
return start(iterator.next(value))
}, error => {
return start(iterator.throw(error));
})
}
start(iterator.next());
};
run(generator); // Save
})();
作用:
1. 是为各种数据结构,提供一个统一的、简便的访问接口。
2. 是使得数据结构的成员能够按某种次序排列。
3. 是 ES6 创造了一种新的遍历命令 for...of
循环,Iterator 接口主要供 for...of
消费。
遍历过程:
1. 创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。
2. 第一次调用指针对象的 next
方法,可以将指针指向数据结构的第一个成员。
3. 第二次调用指针对象的 next
方法,指针就指向数据结构的第二个成员。
4. 不断调用指针对象的 next
方法,直到它指向数据结构的结束位置。
每一次调用 next
方法,都会返回数据结构的当前成员的信息。
具体来说,就是返回一个包含 value
和 done
两个属性的对象。
其中,value
属性是当前成员的值,done
属性是一个布尔值,表示遍历是否结束。
ES6 中,有些数据结构原生具备 Iterator 接口,就可以被 for...of
循环遍历。
原因在于: 这些数据结构原生部署了 Symbol.iterator
属性。
另外一些数据结构没有。凡是部署了 Symbol.iterator
属性的数据结构,就称为部署了遍历器接口。
(() => {
let array = ['save', 'you', 'from', 'anything'];
let iterator = array[Symbol.iterator]();
for (let i = 0; i < array.length; i++) {
console.log(iterator.next()); // { value: 'save', done: false }
} // { value: 'you', done: false }
// { value: 'from', done: false }
// { value: 'anything', done: false }
})();
Symbol.iterator
返回的必须是 遍历器对象 Iterator
。
(() => {
let target = {
data: [],
[Symbol.iterator](){
const self = this;
let index = 0;
function next() {
if (index < self.data.length) {
return {
value: self.data[index++],
done: false
}
} else {
return {
value: undefined,
done: true
}
}
};
let iterator = {
next: next
};
return iterator;
}
}
let array = ['save', 'you', 'from', 'anything'];
target.data.push(...array); // { data: [ 'save', 'you', 'from', 'anything' ] }
console.log(target);
for (let targetValue of target) {
console.log(targetValue); // save
} // you
// from
// anything
})();
(() => {
function Pointer(value) {
this.value = value;
this.next = null;
}
Pointer.prototype[Symbol.iterator] = function () {
let iterator = {
next: next
};
let current = this;
function next() {
if (current) {
let value = current.value;
current = current.next;
return {
value: value,
done: false
};
} else {
return {
done: true
};
}
}
return iterator;
}
let save = new Pointer('save');
let you = new Pointer('you');
let from = new Pointer('from');
let anything = new Pointer('anything');
save.next = you;
you.next = from;
from.next = anything;
for (let value of save) {
console.log(value); // save
} // you
// from
// anything
})();
(() => {
let target = {
0: 'save',
1: 'you',
2: 'from',
3: 'anything',
length: 6,
[Symbol.iterator]: Array.prototype[Symbol.iterator]
};
for (let value of target) {
console.log(value); // save
} // you
// from
// anything
// undefined
// undefined
let errorTarget = { // 必须对应数组的结构的 对象才可以,普通对象不可以
save: 'save',
you: 'you',
from: 'from',
anything: 'anything',
length: 4,
[Symbol.iterator]: Array.prototype[Symbol.iterator]
};
for (let value of errorTarget) {
console.log(value); // undefined
} // undefined
// undefined
// undefined
})();
解构解析
默认调用 Symbol.iterator
。
(() => {
let set = new Set().add('save').add('you').add('from').add('anything');
let [save, you, from, anything] = set;
let [first, ...second] = set;
console.log(save); // save
console.log(you); // you
console.log(from); // from
console.log(anything); // anything
console.log(first); // save
console.log(second); // [ 'you', 'from', 'anything' ]
})();
扩展运算符
let array = [...iterator]
默认调用 Symbol.iterator
。
(() => {
let you = 'you';
console.log([...you]); // [ 'y', 'o', 'u' ]
console.log(['Save', ...you]); // [ 'Save', 'y', 'o', 'u' ]
})();
(() => {
let save = new String('Save'); // 不能写 let save = 'Save'
console.log([...save]); // [ 'S', 'a', 'v', 'e' ]
save[Symbol.iterator] = function () {
let iterator = {
next: next
};
let current = this;
var index = current.length;
function next() {
if (index <= 0) {
return {
done: true
}
} else {
return {
value: current[--index],
done: false
}
}
}
return iterator;
}
console.log([...save]); // [ 'e', 'v', 'a', 'S' ]
})();
(() => {
let generator = {};
generator[Symbol.iterator] = function *() { // Symbol.iterator 可以直接写 generator 函数
yield 2;
yield 3;
yield 3;
};
console.log([...generator]); // [ 2, 3, 3 ]
// 简洁写法
let smartGenerator = {
*[Symbol.iterator](){
yield 'save';
yield 'you';
yield 'from';
yield 'anything';
}
};
for (let value of smartGenerator) {
console.log(value); // save
} // you
// from
// anything
})();
Generator 函数是 ES6 提供的一种异步编程解决方案。
Generator 函数是一个状态机,封装了多个内部状态。
执行 Generator 函数会返回一个遍历器对象,Generator 函数除了状态机,还是一个遍历器对象生成函数。
返回的遍历器对象,可以依次遍历 Generator 函数内部的每一个状态。
Generator 函数是一个普通函数,但是有两个 特征:
function
关键字 与 函数名 之间有 星号。
yield
语句,定义不同的内部状态。
(() => {
function* saveGenerator() {
yield 'save';
yield 'you';
yield 'from';
return 'anything'
};
let save = saveGenerator(); // 调用方法生成 Iterator 对象
console.log(save.next()); // { value: 'save', done: false }
console.log(save.next()); // { value: 'you', done: false }
console.log(save.next()); // { value: 'from', done: false }
console.log(save.next()); // { value: 'anything', done: true }
console.log(save.next()); // { value: undefined, done: true }
save = saveGenerator();
for (let value of save) { // 是 Iterator 就能用 for...of,return 不返回值
console.log(value); // save
} // you
// from
})();
Generator 返回的 Iterator 之所有调用 next
方法才会进入到下一个内部状态。
是因为: 提供了一种可以暂停执行的函数,yield
语句就是暂停标记。
注意: 是调用 next
才执行 yield
后面的语句,而不是 next
执行 yield ???
。
yield
也可以实现 “惰性求值” 的语法功能。
(() => {
function* lazyLoading() {
yield 2200 + 33;
};
console.log(lazyLoading().next()); // { value: 2233, done: false }
})();
Generator 为什么能和 Symbol.iterator 组合?
因为: Symbol.iterator
方法,必须是一个生成 Iterator 的方法,Generator 函数就是 Iterator 生成函数。所以 可以作为 Symbol.iterator
的 方法。
(() => {
let target = {};
target[Symbol.iterator] = function*() {
yield 'save';
yield 'you';
yield 'from';
yield 'anything'
};
for (let value of target) {
console.log(value); // save
} // you
// from
// anything
})();
Generator 执行后,返回一个 Iterator 对象。
这个 Iterator 对象也有 Symbol.iterator
属性。
执行这个 Symbol.iterator
属性上的方法后,得到自己。
(() => {
let generator = function*() {
}
let iterator = generator();
console.log(iterator[Symbol.iterator]() === iterator); // true
})();
yield
语句本身没有 具体返回值,一直返回 undefined
。
next
方法可以加一个参数,作为上一次 yield
的返回值。
(() => {
function* resetTraverse() {
for (let i = 1; true; i++) {
let reset = yield i;
if (reset) {
i = -1;
}
}
}
let generator = resetTraverse();
for (let i = 0; i < 2; i++) {
console.log(generator.next()); // { value: 1, done: false }
} // { value: 2, done: false }
console.log(generator.next(true)); // 设置 reset,i = -1,最后 i++ = 0,{ value: 0, done: false }
for (let i = 0; i < 2; i++) {
console.log(generator.next()); // { value: 1, done: false }
} // { value: 2, done: false }
})();
复杂例子
(() => {
function* func(v) {
let x = 2 * (yield (v + 1));
let y = yield (x / 3);
return (v + x + y);
}
let generatorA = func(2);
// 暂停到 yield (v + 1),调用后 返回 v + 1
// 得到 3
console.log(generatorA.next()); // { value: 3, done: false }
// 暂停到 yield (x / 3),调用后 返回 x / 3
// x = 2 * (yield (v + 1)),yield (v + 1) = undefined
// x = 2 * undefined = NaN
// x / 3 = NaN
console.log(generatorA.next()); // { value: NaN, done: false }
// 暂停到 return,调用后 返回 v + x + y,return 调用后结束
// x = 2 * (yield (v + 1)),yield (v + 1) = undefined
// x = 2 * undefined = NaN
// y = yield (x / 3),yield (x / 3) = undefined
// y = undefined
// v + x + y = 2 + NaN + undefined = NaN
console.log(generatorA.next()); // { value: NaN, done: true }
let generatorB = func(2);
// 暂停到 yield (v + 1),调用后 返回 v + 1
// 得到 3
console.log(generatorB.next()); // { value: 3, done: false }
// 暂停到 yield (x / 3),调用后 返回 x / 3
// x = 2 * (yield (v + 1)),yield (v + 1) = 3
// x = 2 * 3 = 6
// x / 3 = 2
console.log(generatorB.next(3)); // { value: 2, done: false }
// 暂停到 return,调用后 返回 v + x + y,return 调用后结束
// x = 2 * (yield (v + 1)),yield (v + 1) = 3
// x = 2 * 3 = 6
// y = yield (x / 3),yield (x / 3) = 3
// y = 3
// v + x + y = 2 + 6 + 3 = 11
console.log(generatorB.next(3)); // { value: 11, done: true }
})();
第一次 next
的参数值是失效的。
以上面的为例:yield (v + 1)``,调用后 返回
v + 1,完全不涉及到
yield (v + 1)` 的值,只关心了
yield。
v + 1` 的值。
后面是
如果想要第一调用 next 方法时,参数值生效。
需要在 Generator 包一层。
实质上就是完成了:
1. 创建 Generator 方法 + 手动调用一次 next
。
2. 然后这个参数作为 创建 Generator 方法 时的初始值。
(() => {
function wrapperGenerator(generatorFunction) {
return function (...args) {
let generator = generatorFunction(...args);
generator.next();
return generator;
};
}
const wrapped = wrapperGenerator(function*() {
return yield;
});
let generator = wrapped();
console.log(generator.next('Save')); // { value: 'Save', done: true }
console.log(generator.next()); // { value: undefined, done: true }
})();
(() => {
function * generatorFunction() {
for (; ;) {
console.log(yield);
}
}
let generator = generatorFunction();
generator.next();
let save = 'Save';
for (let char of save) {
generator.next(char); // S
} // a
// v
// e
})();
(() => {
function* fibonacci() {
let [previous, current] = [0, 1];
for (; ;) {
[previous, current] = [current, previous + current];
yield current;
}
}
for (let total of fibonacci()) {
if (total > 1000) {
break;
}
console.log(total); // 1
} // 2
// 3
// 5
// 8
// 13
// 21
// 34
// 55
// 89
// 144
// 233
// 377
// 610
// 987
})();
第一种写法 - 侵入式,但是个人还是喜欢在这种。
(() => {
let target = {
save: 'save',
you: 'you',
from: 'from',
anything: 'anything'
};
target[Symbol.iterator] = function*() {
const SYMBOL_TYPE = 'symbol';
let _this = target;
let handler = {
ownKeys(target){
return Reflect
.ownKeys(target)
.filter(key => typeof key !== SYMBOL_TYPE); // 过滤掉 Symbol.???
}
}
let proxy = new Proxy(_this, handler);
for (let key of Object.keys(proxy)) {
yield [key, target[key]];
}
}
for (let [key, value] of target) {
console.log("[key, value] = [", key, ", ", value, "]"); // [key, value] = [ save , save ]
} // [key, value] = [ you , you ]
// [key, value] = [ from , from ]
// [key, value] = [ anything , anything ]
})();
第二种写法 - 无侵入式
(() => {
let target = {
save: 'save',
you: 'you',
from: 'from',
anything: 'anything'
};
function* generatorFunction(target) {
const SYMBOL_TYPE = 'symbol';
let _this = target;
let handler = {
ownKeys(target){
return Reflect
.ownKeys(target)
.filter(key => typeof key !== SYMBOL_TYPE); // 过滤掉 Symbol.???
}
}
let proxy = new Proxy(_this, handler);
for (let key of Object.keys(proxy)) {
yield [key, target[key]];
}
}
for (let [key, value] of generatorFunction(target)) {
console.log("[key, value] = [", key, ", ", value, "]"); // [key, value] = [ save , save ]
} // [key, value] = [ you , you ]
// [key, value] = [ from , from ]
// [key, value] = [ anything , anything ]
})();
Generator 函数返回的遍历器对象,都有一个 throw
方法。
可以在函数体外抛出错误,然后在 Generator 函数体内捕获。
(() => {
let generatorFunction = function*() {
try {
yield;
} catch (e) {
console.log("[内部捕获] = ", e);
}
};
let generator = generatorFunction();
generator.next();
try {
generator.throw('save'); // [内部捕获] = save
generator.throw('you'); // [外部捕获] = you
} catch (e) {
console.log("[外部捕获] = ", e);
}
})();
Generator.throw
可以接受参数,还会被 Generator catch
语句接收,建议 抛 Error 对象。
(() => {
let generatorFunction = function*() {
try {
yield;
} catch (e) {
console.log("[内部捕获] = ", e);
}
};
let generator = generatorFunction();
generator.next();
generator.throw(new Error('异空间错误:2233')); // [内部捕获] = Error: 异空间错误:2233
})();
throw
方法被捕获后,会附带执行下一条 yield
语句。
(() => {
let generatorFunction = function*() {
try {
yield 22;
} catch (e) {
// Nothing to do
}
yield 33;
}
let generator = generatorFunction();
console.log(generator.next()); // { value: 22, done: false }
console.log(generator.throw()); // 已经执行到第二个 yield
// { value: 33, done: false }
console.log(generator.next()); // { value: undefined, done: true }
})();
如果 Generator 内部出现异常没捕获的话,就不会执行下去了。
下次 next
的 value = undefined,done = true
。
(() => {
function* generatorFunction() {
yield 'save'; // 停
console.log("[generator console]"); // 这里不会停
throw new Error(''); // 停
yield 22;
yield 33;
};
function log(generator) {
var v;
try {
v = generator.next();
console.log("[第一次 next]", v); // [第一次 next] { value: 'save', done: false }
} catch (e) {
console.log("[第一次 next - 捕捉错误]", e);
}
try {
v = generator.next(); // [generator console]
console.log("[第二次 next]", v);
} catch (e) {
console.log("[第二次 next - 捕捉错误]", e); // [第二次 next - 捕捉错误] Error
}
// 后续都不执行了
console.log("[第三次 next]", generator.next()); // [第三次 next] { value: undefined, done: true }
console.log("[第四次 next]", generator.next()); // [第四次 next] { value: undefined, done: true }
console.log("[第五次 next]", generator.next()); // [第五次 next] { value: undefined, done: true }
}
log(generatorFunction());
})();
Generator 方法返回的 Iterator 对象,还有一个 return
方法,可以返回给定的值。
(() => {
function* generatorFunction() {
yield '22';
yield '33';
yield '2233';
};
let generator = generatorFunction(); // 提供参数 return
console.log(generator.next()); // { value: '22', done: false }
console.log(generator.next()); // { value: '33', done: false }
console.log(generator.return('return')); // { value: 'return', done: true }
console.log(generator.next()); // { value: undefined, done: true }
console.log(generator.next()); // { value: undefined, done: true }
generator = generatorFunction(); // 不提供参数
console.log(generator.next()); // { value: '22', done: false }
console.log(generator.next()); // { value: '33', done: false }
console.log(generator.return()); // { value: undefined, done: true }
console.log(generator.next()); // { value: undefined, done: true }
console.log(generator.next()); // { value: undefined, done: true }
})();
有 finally
代码块的话,return
会推迟到 finally
,代码块执行完之后才执行。
(() => {
function* generatorFunction() {
yield 1;
try {
yield 2;
yield 3;
yield 4;
} finally {
yield 5;
yield 6;
yield 7;
}
yield 8;
};
let generator = generatorFunction();
console.log(generator.next()); // { value: 1, done: false }
console.log(generator.next()); // { value: 2, done: false }
console.log(generator.return(2233)); // { value: 5, done: false }
console.log(generator.next()); // { value: 6, done: false }
console.log(generator.next()); // { value: 7, done: false }
// 一定要等到 finally 执行完,才会执行 return
console.log(generator.next()); // { value: 2233, done: true }
})();
Generator 方法内部,直接调用 Generator 是没效果的。
(() => {
function* generatorFunction() {
yield 'save';
yield 'you';
generatorFunction();
};
for (let value of generatorFunction()) {
console.log(value); // save
} // you
// generatorFunction() 并没有效果
})();
yield*
就有效。
(() => {
function* otherGeneratorFunction() {
yield 'from';
yield 'anything';
};
function* generatorFunctionA() {
yield 'save';
yield 'you';
yield* otherGeneratorFunction();
};
for (let value of generatorFunctionA()) {
console.log(value); // save
} // you
// from
// anything
// 等同于
function* generatorFunctionB() {
yield 'save';
yield 'you';
for (let value of otherGeneratorFunction()) {
yield value;
}
};
for (let value of generatorFunctionB()) {
console.log(value); // save
} // you
// from
// anything
})();
yield Generator
与 yield* Generator
。
(() => {
function* otherGeneratorFunction() {
yield 2233;
};
/**
* yield Generator
*/
function* generatorFunctionA() {
yield 'save';
yield 'you';
yield otherGeneratorFunction();
};
/**
* yield* Generator
*/
function* generatorFunctionB() {
yield 'save';
yield 'you';
yield* otherGeneratorFunction();
};
let generatorA = generatorFunctionA();
let generatorB = generatorFunctionB();
console.log(generatorA.next().value); // save
console.log(generatorA.next().value); // you
// yield Generator 返回一个 Iterator 对象
console.log(typeof generatorA.next().value); // object
console.log(generatorB.next().value); // save
console.log(generatorB.next().value); // you
// yield* Generator 会遍历 Generator 返回的 Iterator 对象
console.log(generatorB.next().value); // 2233
})();
yield* Generator
等同于 for...of Generator
。
(() => {
function* concatA(previousGenerator, afterGenerator) {
yield previousGenerator;
yield afterGenerator;
};
// 等同于
function* concatB(previousGenerator, afterGenerator) {
for (let value of previousGenerator) {
yield value;
}
for (let value of afterGenerator) {
yield value;
}
};
})();
yield* Generator
的话,会 for...of
这个 Generator。
yield* Iterator
的话,也会 for...of
这个 Iterator。
数组也是有自己的 Iterator。
所有,yield*
数组,就会直接遍历这个数组。
(() => {
function* generatorFunction() {
yield* ['save', 'you', 'from', 'anything'];
};
let generator = generatorFunction();
for (let value of generator) {
console.log(value); // save
} // you
// from
// anything
generator = generatorFunction();
console.log(generator.next()); // { value: 'save', done: false }
console.log(generator.next()); // { value: 'you', done: false }
})();
只要有 Iterator 接口,就可以被 yield*
遍历。
(() => {
function* generatorFunction() {
yield* 'Save';
};
for (let char of generatorFunction()) {
console.log(char); // S
} // a
// v
// e
})();
yield* Generator return
可以作为 yield*
返回的值。
(() => {
function* otherGeneratorFunction() {
yield 22;
yield 33;
return '[ otherGeneratorFunction ]';
};
function* generatorFunction() {
yield 11;
let returnValue = yield* otherGeneratorFunction();
console.log(returnValue);
yield 44;
};
let generator = generatorFunction();
console.log(generator.next()); // { value: 11, done: false }
console.log(generator.next()); // { value: 22, done: false }
console.log(generator.next()); // { value: 33, done: false }
console.log(generator.next()); // [ otherGeneratorFunction ]
// { value: 44, done: false }
console.log(generator.next()); // { value: undefined, done: true }
})();
(() => {
let array = [11, [22, 33, [44, 55, [66, 77]]], [88, 99]];
function* depthTraversal(array) {
if (Array.isArray(array)) {
for (let element of array) {
yield* depthTraversal(element);
}
} else {
yield array;
}
};
for (let value of depthTraversal(array)) {
console.log(value); // 11
} // 22
// 33
// 44
// 55
// 66
// 77
// 88
// 99
})();
(() => {
function Tree(left, current, right) {
this.left = left;
this.current = current;
this.right = right;
};
function* inorder(node) {
if (node) {
yield* inorder(node.left);
yield node.current;
yield* inorder(node.right);
}
};
function makeTree(array) {
if (array.length == 1)return new Tree(null, array[0], null);
return new Tree(makeTree(array[0]), array[1], makeTree(array[2]));
};
let tree = makeTree([[['a'], 'b', ['c']], 'd', [['e'], 'f', ['g']]]);
console.log(tree); // Tree {
// left:
// Tree {
// left: Tree { left: null, current: 'a', right: null },
// current: 'b',
// right: Tree { left: null, current: 'c', right: null } },
// current: 'd',
// right:
// Tree {
// left: Tree { left: null, current: 'e', right: null },
// current: 'f',
// right: Tree { left: null, current: 'g', right: null } } }
for (let node of inorder(tree)) {
console.log(node); // a
} // b
// c
// d
// e
// f
// g
})();
ES6 规定 Generator 返回的 Iterator 是 Generator 的实例。
也继承了 Generator 方法的 prototype 对象上的方法。
(() => {
function* generatorFunction() {
};
generatorFunction.prototype.save = function () {
return 'save';
};
let generator = generatorFunction();
console.log(generator instanceof generatorFunction); // true
console.log(generator.save()); // save
})();
Generator 作为普通构造函数,this
不会在 Iterator 中生效。
(() => {
function* generatorFunction() {
this.save = 'save';
};
let generator = generatorFunction();
console.log(generator instanceof generatorFunction); // true
console.log(generator.save); // undefined
})();
Generator 作为一个对象,又可以 next
,又可以获得正常 this
。
但是:对象不统一。
(() => {
function* generatorFunction() {
this.save = 'save';
yield this.you = 'you';
};
let target = {};
let generator = generatorFunction.call(target); // this = target
console.log(generator.next()); // { value: 'you', done: false }
console.log(generator.next()); // { value: undefined, done: true }
// this 代码,都保存在 target 上了
console.log(target); // { save: 'save', you: 'you' }
console.log(target.save); // save
console.log(target.you); // you
})();
Generator 作为一个对象,又可以 next
,又可以获得正常 this
。
但是:对象统一。
(() => {
function* generatorFunction() {
this.save = 'save';
yield this.you = 'you';
};
let generator = generatorFunction.call(generatorFunction.prototype); // 传入 自身的 prototype
console.log(generator.next()); // { value: 'you', done: false }
console.log(generator.next()); // { value: undefined, done: true }
console.log(generator); // {}
console.log(generator.save); // save
console.log(generator.you); // you
})();
(() => {
function* loadUI() {
showLoadingScreen();
yield loadUIDataAsynchronously();
hideLoadingScreen();
};
function showLoadingScreen() {
console.log("[showLoadingScreen]");
};
function loadUIDataAsynchronously() {
console.log("[loadUIDataAsynchronously]");
};
function hideLoadingScreen() {
console.log("[hideLoadingScreen]");
};
let loader = loadUI();
loader.next(); // [showLoadingScreen]
// [loadUIDataAsynchronously]
loader.next(); // [hideLoadingScreen]
})();
(() => {
function* readFile(filePath) {
let file = new FileReader(filePath);
try {
while (!file.eof) {
yield parseInt(file.readLine(), 10);
}
} catch (e) {
console.log(e);
} finally {
file.close();
}
};
})();