1. 柯里化
function curry(func) {
return function curried(...args) {
if (args.length >= func.length) {
return func.apply(this, args);
} else {
return function(...args2) {
return curried.apply(this, args.concat(args2));
}
}
};
}
用例:
function sum(a, b, c) {
return a + b + c;
}
let curriedSum = curry(sum);
alert( curriedSum(1, 2, 3) ); // 6,仍然可以被正常调用
alert( curriedSum(1)(2,3) ); // 6,对第一个参数的柯里化
alert( curriedSum(1)(2)(3) ); // 6,全柯里化
2. Function.prototype.call
Function.prototype.call = function (obj, ...args) {
let res;
if(!obj) {
res = this(...args);
} else {
obj.fn = this;
res = obj.fn(...args);
delete obj.fn;
}
return res;
}
用例:
const person = {
name: 'haha',
selfTalk(age) {
console.log(this.name, age);
}
}
const animal = {
name: 'lion',
}
person.selfTalk.call(animal, 20)
console.log(animal);
3. promisify
function promisify(f) {
return function (...args) { // 返回一个包装函数(wrapper-function)
return new Promise((resolve, reject) => {
function callback(err, result) { // 我们对 f 的自定义的回调
if (err) {
reject(err);
} else {
resolve(result);
}
}
args.push(callback); // 将我们的自定义的回调附加到 f 参数(arguments)的末尾
f.call(this, ...args); // 调用原始的函数
});
};
};
用例:
let loadScriptPromise = promisify(loadScript);
loadScriptPromise(...).then(...);
4.删除数组元素
Array.prototype.remove = function(dx) {
if(isNaN(dx) || dx > this.length){
return false;
}
for(var i = 0, n = 0; i < this.length; i++) {
if(this[i] != this[dx]) {
this[n++] = this[i];
}
}
this.length -= 1;
};
用例:
var colors = ["red", "blue", "grey"];
colors.remove(1);
console.log(colors); // ["red", "grey"]
5.EventHub
class EventHub {
eventCenter = {}
on(eventName, callback) {
if (typeof callback !== 'function') {
console.log('回调必须为函数');
return
}
if (eventName in this.eventCenter) {
this.eventCenter[eventName].eventList.push(callback);
} else {
this.eventCenter[eventName] = {
name: eventName,
eventList: [callback]
};
}
}
off(eventName, callback) {
if (eventName in this.eventCenter) {
this.eventCenter[eventName].eventList.forEach((fn, index) => {
if(fn === callback) this.eventCenter[eventName].eventList.splice(index, 1)
})
} else {
console.log('解绑的事件不存在')
}
}
emit(eventName, ...args) {
if (eventName in this.eventCenter) {
this.eventCenter[eventName].eventList.forEach(fn => {
fn(...args);
})
} else {
console.log('触发的事件不存在')
}
}
}
用例:
const e = new EventHub();
function fn1() {
console.log('clicked');
}
e.on('click', fn1)
e.on('click', function (p1, p2) {
console.log('clicked2' + p1 + p2);
})
e.off('click', fn1);
e.emit('click', 'hello', 'world');
6.Promise
function resolve(result) {
if (this.state !== Promise2.PENDING) return;
this.state = Promise2.FULLFILLED;
nextTick(() => {
this.stack.forEach(({ success, fail, promise2 }) => {
if (typeof success !== 'function') {
resolve.call(promise2, result);
return
}
try {
const res = success(result);
resolveWith(promise2, res);
} catch (err) {
reject.call(promise2, err);
}
})
})
}
function reject(reason) {
if (this.state !== Promise2.PENDING) return;
this.state = Promise2.REJECTED;
nextTick(() => {
this.stack.forEach(({ success, fail, promise2 }) => {
if (typeof fail !== 'function') {
resolve.call(promise2, reason);
return
}
try {
console.log(2);
const res = fail(reason);
console.log(3);
resolveWith(promise2, res);
} catch (err) {
reject.call(promise2, err);
}
})
})
}
function resolveWith(promise, x) {
if (promise === x) {
reject.call(promise, new TypeError(''));
} else if (x instanceof Promise2) {
x.then((result) => {
resolve.call(promise, result)
}, (reason) => {
reject.call(promise, reason)
});
} else if (typeof x === 'object') {
let then
try {
// 因为then可能是一个 get 属性,所以有可能报错
then = x.then;
if (typeof then === 'function') {
try {
then.call(x, (result) => {
resolveWith(promise, result)
}, (reason) => {
reject.call(promise, reason)
});
} catch (err) {
reject.call(promise, err)
}
} else {
resolve.call(promise, x);
}
} catch (err) {
reject.call(promise, err);
}
} else {
resolve.call(promise, x);
}
}
export class Promise2 {
static PENDING = 'PENDING'
static FULLFILLED = 'FULLFILLED'
static REJECTED = 'REJECTED'
constructor(fun) {
if (typeof fun !== 'function') {
throw new Error('Promise参数必须是一个函数');
}
fun(resolve.bind(this), reject.bind(this));
}
private stack = []
private state = Promise2.PENDING
then(success?, fail?) {
const promise2 = new Promise2(() => { });
this.stack.push({
success,
fail,
promise2
})
return promise2;
}
}
const nextTick = function () {
var callbacks = [];
function resolveCallbacks() {
const copys = callbacks.slice(0);
copys.forEach(cb => {
cb();
});
callbacks.length = 0;
}
if (typeof process !== undefined && process.nextTick) {
return process.nextTick;
} else {
var counter = 1;
var textNode = document.createTextNode(String(counter));
var observer = new MutationObserver(resolveCallbacks);
observer.observe(textNode, {
characterData: true
});
return function (fun) {
callbacks.push(fun);
counter = (counter + 1) % 2;
textNode.data = String(counter);
}
}
}()
7. JSONP
const jsonp = function (url, data) {
return new Promise((resolve, reject) => {
// 初始化url
let dataString = url.indexOf('?') === -1 ? '?' : '&'
let callbackName = `jsonpCB_${Date.now()}`
url += `${dataString}callback=${callbackName}`
if (data) {
// 有请求参数,依次添加到url
for (let k in data) {
url += `&${k}=${data[k]}`
}
}
let jsNode = document.createElement('script')
jsNode.src = url
// 触发callback,触发后删除js标签和绑定在window上的callback
window[callbackName] = result => {
delete window[callbackName]
document.body.removeChild(jsNode)
if (result) {
resolve(result)
} else {
reject('没有返回数据')
}
}
// js加载异常的情况
jsNode.addEventListener('error', () => {
delete window[callbackName]
document.body.removeChild(jsNode)
reject('JavaScript资源加载失败')
}, false)
// 添加js节点到document上时,开始请求
document.body.appendChild(jsNode)
})
}
jsonp('http://192.168.0.103:8081/jsonp', {a: 1, b: 'heiheihei'})
.then(result => { console.log(result) })
.catch(err => { console.error(err) })