1、手写 bind、apply、call
Function.prototype.bind = function (context, ...args) {
context = context || window;
const fnSymbol = Symbol("fn");
context[fnSymbol] = this;
return function (..._args) {
args = args.concat(_args);
context[fnSymbol](...args);
delete context[fnSymbol];
}
}
Function.prototype.apply = function (context, argsArr) {
context = context || window;
const fnSymbol = Symbol("fn");
context[fnSymbol] = this;
context[fnSymbol](...argsArr);
delete context[fnSymbol];
}
Function.prototype.call = function (context, ...args) {
context = context || window;
const fnSymbol = Symbol("fn");
contet[fnSymbol] = this;
context[fnSymbol](...args);
delete context[fnSymbol];
}
2、手写 Promise
class myPromise {
static pending = 'pending';
static fulfilled = 'fulfilled';
static rejected = 'rejected';
constructor(executor) {
this.status = myPromise.pending;
this.value = undefined;
this.reason = undefined;
this.callbacks = [];
executor(this._resolve.bind(this), this._reject.bind(this));
}
then(onFulfilled, onRejected) {
return new myPromise((nextResolve, nextReject) => {
this._handler({
nextResolve,
nextReject,
onFulfilled,
onRejected
});
});
}
_resolve(value) {
if (value instanceof myPromise) {
value.then(
this._resolve.bind(this),
this._reject.bind(this)
);
return;
}
this.value = value;
this.status = myPromise.fulfilled;
this.callbacks.forEach(cb => this._handler(cb));
}
_reject(reason) {
if (reason instanceof myPromise) {
reason.then(
this._resolve.bind(this),
this._reject.bind(this)
);
return;
}
this.reason = reason;
this.status = myPromise.rejected;
this.callbacks.forEach(cb => this._handler(cb));
}
_handler(callback) {
const {
onFulfilled,
onRejected,
nextResolve,
nextReject
} = callback;
if (this.status === myPromise.pending) {
this.callbacks.push(callback);
return;
}
if (this.status === myPromise.fulfilled) {
const nextValue = onFulfilled ? onFulfilled(this.value) : this.value;
nextResolve(nextValue);
return;
}
if (this.status === myPromise.rejected) {
const nextReason = onRejected ? onRejected(this.reason) : this.reason;
nextReject(nextReason);
}
}
}
3、手写 实现promise.all 方法
Promise.all = (arr) => {
return new Promise((resolve, reject) => {
let res = [];
let count = 0;
for (let i = 0; i < arr.length; i++) {
Promise.resolve(arr[i]).then((value) => {
res[i] = value;
count ++;
if(count === arr.length) {
resolve(res);
}
}).catch((reason) => {
reject(reason);
})
}
})
}
4、手写 实现promise.prototype.finally 方法
Promise.prototype.finally = function(callback) {
return this.then((value) => {
return Promise.resolve(callback()).then(() => value);
}),
(err) => {
return Promise.resolve(callback()).then(() => {throw err});
}
}
5、手写 Promise.allSeettled 方法, 需要返回所有promise的状态和结果
function PromiseAllSettled(promiseArray) {
return new Promise(function (resolve, reject) {
if (!Array.isArray(promiseArray)) {
return reject(new TypeError('arguments muse be an array'))
}
let counter = 0;
const promiseNum = promiseArray.length;
const resolvedArray = [];
for (let i = 0; i < promiseNum; i++) {
Promise.resolve(promiseArray[i])
.then((value) => {
resolvedArray[i] = {
status: 'fulfilled',
value
};
})
.catch(reason => {
resolvedArray[i] = {
status: 'rejected',
reason
};
})
.finally(() => {
counter++;
if (counter == promiseNum) {
resolve(resolvedArray)
}
})
}
})
}
6、手写 Promise.race
function myPromiseRace(arr) {
return new Promise((resolve, reject) => {
for(var i = 0; i < arr.length; i++) {
return arr[i].then(resolve,reject);
}
})
}
7、手写 数据偏平化
function flatten(arr) {
let result = [];
for (let i = 0; i < arr.length; i++) {
if(Array.isArray(arr[i])) {
result = result.concat(flatten(arr[i]));
} else {
result = result.concat(arr[i]);
}
}
return result;
}
const a = [1, [2, [3, 4]]];
console.log(flatten(a))
8、手写 实现柯里化
function createCurry(func, args) {
var argity = func.length;
var args = args || [];
return function() {
var _args = [].slice.apply(arguments);
args.push(_args);
if(args.length < argity) {
return createCurry.call(this, func, args);
}
return func.apply(this, args);
}
}
9、手写 实现深、浅拷贝函数
function shallowClone(obj) {
let cloneObj = {};
for (let i in obj) {
cloneObj[i] = obj[i];
} return cloneObj;
}
function deepCopy(obj) {
if (typeof obj === 'object') {
var result = obj.constructor === Array ? [] : {};
for (var i in obj) {
result[i] = typeof obj[i] === 'object' ? deepCopy(obj[i]) : obj[i];
}
} else {
var result = obj;
}
return result;
}
10、手写 防抖、节流
- 防抖:动作绑定事件,动作发生后一定时间后触发事件,在这段时间内,如果该动作又发生,则重新等待一定时间再触发事件。
function debounce(func, time) {
let timer = null;
return () => {
clearTimeout(timer);
timer = setTimeout(()=> {
func.apply(this, arguments)
}, time);
}
}
- 节流: 动作绑定事件,动作发生后一段时间后触发事件,在这段时间内,如果动作又发生,则无视该动作,直到事件执行完后,才能重新触发。
function throtte(func, time){
let activeTime = 0;
return () => {
const current = Date.now();
if(current - activeTime > time) {
func.apply(this, arguments);
activeTime = Date.now();
}
}
}
11、手写 instanceof
function myInstanceof(left, right) {
let protoType = right.protoType;
left = left.__proto__;
while(true) {
if(!left) return false;
if(left == protoType) return true;
left = left.__proto__;
}
}
console.log(myInstanceof([],Array));
12、手写 New
function Person(name,age) {
this.name = name;
this.age = age;
}
Person.protoType.sayHi() = function() {
console.log('我是',this.name);
}
let p1 = new Person('abc',10);
function create() {
let obj = {};
let fn = [].shift.call(arguments);
obj.__proto__ = fn.prototype;
let res = fn.apply(obj,arguments);
return typeof res === 'Object' ? res : obj;
}
let p2 = create(Person,'def',13);
p2.sayHi();
13、手写 快速排序
function quicksort(arr) {
if(arr.length <= 1) return arr;
let pivotIndex = arr.length >> 1;
let pivot = arr.splice(pivotIndex,1)[0];
let left = [];
let right = [];
for(var i = 0; i < arr.length; i++) {
if(arr[i] <= pivot) {
left.push(arr[i]);
}else {
right.push(arr[i]);
}
}
return quicksort(left).concat(pivot, quicksort(right));
}
console.log(quicksort([9,4,5,1,7,2]));
14、异步笔试题,请写出下面代码的运行结果
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
async function async2() {
console.log('async2');
}
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0)
async1();
new Promise(function(resolve) {
console.log('promise1');
resolve();
}).then(function() {
console.log('promise2');
});
console.log('script end');
15、数组排序
1、JS 的全排列
function permutate(str) {
var result = [];
if(str.length > 1) {
var left = str[0];
var rest = str.slice(1,str.length);
var preResult = permutate(rest);
for(var i=0; i<preResult.length; i++){
for(var j=0;j<preResult[i].length; j++) {
var tmp = preResult[i],slice(0, j) + left + preResult[i].slice(j,preResult[i].length);
result.push(tmp);
}
}
} else if (str.length== 1) {
return [str];
}
return result;
}
2、冒泡排序
function bubbleSort(arr) {
let len = arr.length
for (let i = 0; i < len - 1; i++) {
for (let j = 0; j < len - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
let num = arr[j]
arr[j] = arr[j + 1]
arr[j + 1] = num
}
}
}
return arr
}
console.log(bubbleSort([2, 3, 1, 5, 4]))
3、sort排序
const arr = [3, 2, 4, 1, 5]
arr.sort((a, b) => a - b)
console.log(arr)
const arr = ['b', 'c', 'a', 'e', 'd']
arr.sort()
console.log(arr)
16、编写render函数, 实现template render功能
const year = '2021';
const month = '10';
const day = '01';
let template = '${year}-${month}-${day}';
let context = { year, month, day };
const str = render(template)({year,month,day});
console.log(str)
function render(template) {
return function(context) {
return template.replace(/${(.*?)}/g, (match, key) => context[key]);
}
}
17、发布订阅模式
class EventEmitter {
constructor() {
this.cache = {}
}
on(name, fn) {
if (this.cache[name]) {
this.cache[name].push(fn)
} else {
this.cache[name] = [fn]
}
}
off(name, fn) {
const tasks = this.cache[name]
if (tasks) {
const index = tasks.findIndex((f) => f === fn || f.callback === fn)
if (index >= 0) {
tasks.splice(index, 1)
}
}
}
emit(name, once = false) {
if (this.cache[name]) {
const tasks = this.cache[name].slice()
for (let fn of tasks) {
fn();
}
if (once) {
delete this.cache[name]
}
}
}
}
const eventBus = new EventEmitter()
const task1 = () => { console.log('task1'); }
const task2 = () => { console.log('task2'); }
eventBus.on('task', task1)
eventBus.on('task', task2)
eventBus.off('task', task1)
setTimeout(() => {
eventBus.emit('task')
}, 1000)