Function.prototype.myCall = function () { let thisVal = arguments[0] // 存call第一个参数执行上下文 const isStrict = (function () { return this === undefined })() // 判断当前环境是否是严格模式 if (!isStrict) { // 非严格模式 if (thisVal === null || thisVal === undefined) { // thisVal 没传或者是null, undefined thisVal = (function () { return this })() // 则赋值为window或者node环境参数 } } else { // 严格模式 const thisValType = typeof thisVal // 先处理可能输入的不同数据格式 if (thisValType === 'number') { thisVal = new Number(thisVal) } if (thisValType === 'string') { thisVal = new String(thisVal) } if (thisValType === 'boolean') { thisVal = new Boolean(thisVal) } } const otherParams = [...arguments].slice(1) // call其他参数 const fn = this // 当前this就是调用call的方法 if (thisVal === null || thisVal === undefined) { // 严格模式 并且没有指定第一个参数或者第一个参数的值本身就是null或undefined,此时将目标函数当成普通函数执行并返回其结果即可 return fn(...otherParams) } // 否则,让目标函数成为thisArg对象的成员方法,然后调用它 ??? // 直观上来看,可以直接把目标函数赋值给对象属性,比如func属性,但是可能func属性本身就存在于thisArg对象上 // 所以,为了防止覆盖掉thisArg对象的原有属性,必须创建一个唯一的属性名,可以用Symbol实现,如果环境不支持Symbol,可以通过uuid算法来构造一个唯一值。 var uniquePropName = Symbol(thisVal) thisVal[uniquePropName] = fn return thisVal[uniquePropName](...otherParams) } Function.prototype.myApply = function () { let thisVal = arguments[0] // 存call第一个参数执行上下文 const isStrict = (function () { return this === undefined })() // 判断当前环境是否是严格模式 if (!isStrict) { // 非严格模式 if (thisVal === null || thisVal === undefined) { // thisVal 没传或者是null, undefined thisVal = (function () { return this })() // 则赋值为window或者node环境参数 } } else { // 严格模式 const thisValType = typeof thisVal // 先处理可能输入的不同数据格式 if (thisValType === 'number') { thisVal = new Number(thisVal) } if (thisValType === 'string') { thisVal = new String(thisVal) } if (thisValType === 'boolean') { thisVal = new Boolean(thisVal) } } const otherParams = Array.isArray(arguments[1]) ? [...arguments[1]] : arguments[1] // call其他参数 const fn = this // 当前this就是调用call的方法 if (thisVal === null || thisVal === undefined) { // 严格模式 并且没有指定第一个参数或者第一个参数的值本身就是null或undefined,此时将目标函数当成普通函数执行并返回其结果即可 return fn(...otherParams) } // 否则,让目标函数成为thisArg对象的成员方法,然后调用它 ??? // 直观上来看,可以直接把目标函数赋值给对象属性,比如func属性,但是可能func属性本身就存在于thisArg对象上 // 所以,为了防止覆盖掉thisArg对象的原有属性,必须创建一个唯一的属性名,可以用Symbol实现,如果环境不支持Symbol,可以通过uuid算法来构造一个唯一值。 var uniquePropName = Symbol(thisVal) thisVal[uniquePropName] = fn return thisVal[uniquePropName](...otherParams) } function curry(fn) { let args = [] function curried() { args = [...args, ...arguments] return curried } curried.toString = function(){ return fn.myCall(null, ...args) } return curried }
Promise.all = function (iterators) { return new Promise((resolve, reject) => { if (!iterators || iterators.length === 0) { resolve([]); } else { let count = 0; // 计数器,用于判断所有任务是否执行完成 let result = []; // 结果数组 for (let i = 0; i < iterators.length; i++) { // 考虑到iterators[i]可能是普通对象,则统一包装为Promise对象 Promise.resolve(iterators[i]).then( (data) => { result[i] = data; // 按顺序保存对应的结果 // 当所有任务都执行完成后,再统一返回结果 if (++count === iterators.length) { resolve(result); } }, (err) => { reject(err); // 任何一个Promise对象执行失败,则调用reject()方法 return; } ); } } }); };
Promise.race = function (iterators) { return new Promise((resolve, reject) => { for (const iter of iterators) { Promise.resolve(iter) .then((res) => { resolve(res); }) .catch((e) => { reject(e); }); } }); };