- JS 模块化
AMD: require.js 为代表,依赖前置,一律先加载再使用。
CMD: sea.js 为代表,依赖就近原则。
UMD: 兼容AMD和commonJS规范的同时,还兼容全局引用的方式。
ES6 import/export
15.你从未注意的隐藏危险: target = "\_blank" 和 "opener"
// 最佳实践
<a href="https://an.evil.site" target="_blank"
rel="noopener noreferrer nofollow">
Enter an "evil" website
</a>
16.阶乘
function factorial(num, sum = 1) {
if(num <= 1)return sum;
sum *= num;
return factorial(--num, sum); // 尾递归
}
factorial(3) // -> 6
17.柯里化
const curry = (fn , args = []) => {
return (...rets) => {
const allArgs = args.concat(rets);
if(allArgs.length < fn.length) {
return curry(fn, allArgs);
} else {
return fn.apply(this, allArgs);
}
}
}
function multiFn(a, b, c) {
return a * b * c;
}
var multi = curry(multiFn);
multi(2)(3)(4);
multi(2,3,4);
multi(2)(3,4);
multi(2,3)(4);
- 「中高级前端面试」JavaScript 手写代码无敌秘籍
- 实现一个 Promise 《图解 Promise 实现原理》
// Promise 简单的实现
function APromise(fn) {
const that = this;
that.status = "pending"; // Promise初始状态为pending
that.data = undefined; // Promise的值
that.resCbs = []; // APromise resolve回调函数集合
that.rejCbs = []; // APromise reject回调函数集合
function resolve(data) {
if (that.status === "pending") {
that.status = "resolved";
that.data = data;
setTimeout(() => {
that.resCbs.forEach((cb) => cb(data));
});
}
}
function reject(data) {
if (that.status === "pending") {
that.status = "rejected";
that.data = data;
setTimeout(() => {
that.rejCbs.forEach((cb) => cb(data));
});
}
}
try {
fn(resolve, reject); // 执行传进来的函数,传入resolve, reject参数
} catch (e) {
reject(e);
}
}
APromise.prototype.then = function (onRes = (v) => v, onRej = (j) => j) {
const that = this;
if (that.status === "resolved") {
// 这里promise的状态已经确定是resolved,所以调用onResolved
return new APromise((resolve, reject) => {
setTimeout(() => {
try {
// ret是onRes的返回值
const ret = onRes(that.data);
if (ret instanceof APromise) {
// 如果ret是一个promise,则取其值作为新的promise的结果
ret.then(resolve, reject);
} else {
// 否则,以它的返回值作为新的promise的结果
resolve(ret);
}
} catch (e) {
// 如果出错,以捕获到的错误作为promise2的结果
reject(e);
}
});
});
}
// 这里的逻辑跟前面一样,不再赘述
if (that.status === "rejected") {
return new APromise((resolve, reject) => {
setTimeout(() => {
try {
const ret = onRej(that.data);
if (ret instanceof APromise) {
ret.then(resolve, reject);
} else {
reject(ret);
}
} catch (e) {
reject(e);
}
});
});
}
if (that.status === "pending") {
// 如果当前的Promise还处于pending状态,则不能确定调用
// onResolved还是onRejecte,只能等到Promise状态确定后,
// 才能确定如何处理
return new APromise((resolve, reject) => {
that.resCbs.push(() => {
setTimeout(() => {
try {
const ret = onRes(that.data);
if (ret instanceof APromise) {
ret.then(resolve, reject);
} else {
resolve(ret);
}
} catch (e) {
reject(e);
}
});
});
that.rejCbs.push(() => {
setTimeout(() => {
try {
const ret = onRej(that.data);
if (ret instanceof APromise) {
ret.then(resolve, reject);
} else {
reject(ret);
}
} catch (e) {
reject(e);
}
});
});
});
}
};
// 顺便实现一下catch方法
APromise.prototype.catch = function (onRej) {
return this.then(null, onRej);
};
const p = new APromise(function (resolve, reject) {
setTimeout(function () {
resolve(1);
}, 2000);
});
p.then(function (v) {
console.log(v);
return 2;
})
.then(function (v) {
console.log(v);
return new APromise(function (resolve, reject) {
setTimeout(function () {
resolve(3);
}, 3000);
});
})
.then(function (v) {
console.log(v);
});
/**
*实现promise中的all方法
*/
Promise.prototype.all = function (array) {
judgeType(array);
let count = 0;
const total = array.length;
const ret = [];
return new Promise((resolve, reject) => {
array.forEach((element) => {
element.then((res) => {
ret.push(res);
count++;
if (count === total) {
resolve(ret);
}
});
element.catch((err) => {
reject(err);
});
});
});
};
/**
*类型的判断
*/
function judgeType(array) {
if (array instanceof Array) {
array.forEach((item) => {
if (!(item instanceof Promise)) {
throw "该参数的每一项必须是Promise的实例";
}
});
} else {
throw "必须是数组哦";
}
}
var p1 = Promise.resolve(1),
p2 = Promise.resolve(2),
p3 = Promise.resolve(3);
all = function (promises) {
const total = promises.length;
const ret = [];
let count = 0;
return new Promise((resolve, reject) => {
promises.forEach((item) => {
item.then((res) => {
ret.push(res);
count++;
if (count === total) {
return resolve(ret);
}
});
item.catch((err) => {
return reject(err);
});
});
});
};
all([p1, p2, p3]).then(function (results) {
//then方法不会被执行
console.log(results);
}).catch(function (e){
//catch方法将会被执行,输出结果为:2
console.log(2);
});
/**
*实现promise中的race方法
*/
Promise.prototype.race = function (promises) {
return new Promise((resolve, reject) => {
promises.forEach((item) => {
Promise.resolve(item).then(
(res) => {
return resolve(res);
},
(err) => {
return reject(err);
}
);
});
});
};
var p1 = new Promise(function (resolve, reject) {
setTimeout(resolve, 500, "500");
});
var p2 = new Promise(function (resolve, reject) {
setTimeout(resolve, 600, "600");
});
race([p1, p2]).then(function (result) {
console.log(result); // '2018' 因为2018更快
});
/**
*实现promise中的finally方法
*/
Promise.prototype.finally = function (onFinally) {
return this.then(
/* onFulfilled */
(res) => Promise.resolve(onFinally()).then(() => res),
/* onRejected */
(err) =>
Promise.resolve(onFinally()).then(() => {
throw err;
})
);
};
// test
new Promise((resolve) => {
setTimeout(() => {
resolve(1);
}, 500);
})
.then((res) => {
console.log(res);
return new Promise((resolve) => {
setTimeout(() => {
resolve(2);
}, 500);
});
})
.then(console.log);
//Promise 完整的实现
class Promise {
callbacks = [];
state = 'pending';//增加状态
value = null;//保存结果
constructor(fn) {
fn(this._resolve.bind(this), this._reject.bind(this));
}
then(onFulfilled, onRejected) {
return new Promise((resolve, reject) => {
this._handle({
onFulfilled: onFulfilled || null,
onRejected: onRejected || null,
resolve: resolve,
reject: reject
});
});
}
catch(onError) {
return this.then(null, onError);
}
finally(onDone) {
if (typeof onDone !== 'function') return this.then();
let Promise = this.constructor;
return this.then(
value => Promise.resolve(onDone()).then(() => value),
reason => Promise.resolve(onDone()).then(() => { throw reason })
);
}
static resolve(value) {
if (value && value instanceof Promise) {
return value;
} else if (value && typeof value === 'object' && typeof value.then === 'function') {
let then = value.then;
return new Promise(resolve => {
then(resolve);
});
} else if (value) {
return new Promise(resolve => resolve(value));
} else {
return new Promise(resolve => resolve());
}
}
static reject(value) {
if (value && typeof value === 'object' && typeof value.then === 'function') {
let then = value.then;
return new Promise((resolve, reject) => {
then(reject);
});
} else {
return new Promise((resolve, reject) => reject(value));
}
}
static all(promises) {
return new Promise((resolve, reject) => {
let fulfilledCount = 0
const itemNum = promises.length
const rets = Array.from({ length: itemNum })
promises.forEach((promise, index) => {
Promise.resolve(promise).then(result => {
fulfilledCount++;
rets[index] = result;
if (fulfilledCount === itemNum) {
resolve(rets);
}
}, reason => reject(reason));
})
})
}
static race(promises) {
return new Promise(function (resolve, reject) {
for (let i = 0; i < promises.length; i++) {
Promise.resolve(promises[i]).then(function (value) {
return resolve(value)
}, function (reason) {
return reject(reason)
})
}
})
}
_handle(callback) {
if (this.state === 'pending') {
this.callbacks.push(callback);
return;
}
let cb = this.state === 'fulfilled' ? callback.onFulfilled : callback.onRejected;
if (!cb) {//如果then中没有传递任何东西
cb = this.state === 'fulfilled' ? callback.resolve : callback.reject;
cb(this.value);
return;
}
let ret;
try {
ret = cb(this.value);
cb = this.state === 'fulfilled' ? callback.resolve : callback.reject;
} catch (error) {
ret = error;
cb = callback.reject
} finally {
cb(ret);
}
}
_resolve(value) {
if(this.state !== 'pending') return
if (value && (typeof value === 'object' || typeof value === 'function')) {
var then = value.then;
if (typeof then === 'function') {
then.call(value, this._resolve.bind(this), this._reject.bind(this));
return;
}
}
this.state = 'fulfilled';//改变状态
this.value = value;//保存结果
this.callbacks.forEach(callback => this._handle(callback));
}
_reject(error) {
if(this.state !== 'pending') return
this.state = 'rejected';
this.value = error;
this.callbacks.forEach(callback => this._handle(callback));
}
}