无敌手写秘籍
1、New
首先要知道 new 到底做了什么:
- (1) 在内存中创建一个新对象。
- (2) 这个新对象内部的 [[Prototype]] 特性被赋值为构造函数的 prototype 属性。
- (3) 构造函数内部的 this 被赋值为这个新对象(即 this 指向新对象)。
- (4) 执行构造函数内部的代码(给新对象添加属性)。
- (5) 如果构造函数返回非空对象,则返回该对象;否则,返回刚创建的新对象。
js
/**
*
* @param {Function} func 构造函数
* @param {...any} args
*/
const myNew = function (func, ...args) {
if (typeof func !== 'function') {
return new TypeError('this is not a function');
}
// 创建一个空对象,指定原型为 func.prototype
const obj = Object.create(func.prototype);
// 绑定 this 并执行构造函数内部代码给新对象加上属性
const result = func.apply(obj, args);
// 如果构造函数返回非空对象,则返回该对象;否则,返回刚创建的新对象。
return result && result instanceof Object ? result : obj;
};
// 测试
// function Person(name, age) {
// this.name = name;
// this.age = age;
// }
// 用来测试返回引用数据类型
function Person(name, age) {
this.name = name;
this.age = age;
return function () {
console.log('返回引用数据类型');
};
}
console.log('myNew');
const jing = myNew(Person, 'jing', 22);
console.log(jing);
jing();
console.log('new');
const hao = new Person('hao', 23);
console.log(hao);
hao();2、instanceof
js
// 基于原型链一直向上查找,知道达到 object 还未找到返回 false
const myInstanceof = (left, right) => {
while (left) {
if (left === right.prototype) {
return true;
}
left = left.__proto__;
}
return false;
};
console.log(myInstanceof(2, Number)); // true
console.log(myInstanceof([], Number)); // false
console.log(myInstanceof([], Object)); // true3、call、apply
js
Function.prototype.myCall = function (thisArg, ...args) {
if (!thisArg) {
// thisArg 为 null 或者是 undefined
thisArg = typeof window === 'undefined' ? global : window;
}
// 保存this
thisArg.fn = this;
// 执行代码
let res = thisArg.fn(...args); //重点代码,利用this指向,相当于context.caller(...args)
// 删除变量 释放空间
delete thisArg.fn;
// 返回结果
return res;
};
var foo = {
name: 'Selina'
};
var name = 'Chirs';
function bar(job, age) {
console.log(this.name);
console.log(job, age);
}
bar.myCall(foo, 'programmer', 20);
// Selina programmer 20
bar.myCall(null, 'teacher', 25);
// 浏览器环境: Chirs teacher 25; node 环境: undefined teacher 25
Function.prototype.myApply = function (thisArg, args) {
if (!thisArg) {
// thisArg 为 null 或者是 undefined
thisArg = typeof window === 'undefined' ? global : window;
}
// 保存this
thisArg.fn = this;
// 执行代码
let res = thisArg.fn(...args); //重点代码,利用this指向,相当于context.caller(...args)
// 删除变量 释放空间
delete thisArg.fn;
// 返回结果
return res;
};
const numbers = [5, 6, 2, 3, 7];
// Function.prototype.myApply()
console.log('Function.prototype.myApply()');
const max = Math.max.myApply(null, numbers);
console.log(max); // 7
// Function.prototype.apply()
console.log('Function.prototype.apply()');
const min = Math.min.apply(null, numbers);
console.log(min); // 24、bind
js
Function.prototype.myBind = function (thisArg) {
// 设置 fn 为调用 myBind 的函数
const fn = this;
// 得到调用 myBind 函数时传递的参数
const otherArgs = [...arguments].slice(1);
// 定义一个返回的函数
const result = function () {
// 得到执行该函数时的参数
const resultArgs = [...arguments];
const isNew = this instanceof result;
return fn.apply(isNew ? this : thisArg, otherArgs.concat(resultArgs));
};
// 绑定原型,保证原函数的原型对象的属性不丢失,result 是调用 myBind 要返回的函数,下面的 this 是调用 myBind 的函数。把 this 上的原型绑定到返回的函数上面。
result.prototype = this.prototype;
// 返回结果
return result;
};
// 测试代码
function Animal(name, color) {
this.name = name;
this.color = color;
}
Animal.prototype.say = function () {
return `I'm a ${this.color} ${this.name}`;
};
const Cat = Animal.myBind(null, 'cat');
const cat = new Cat('white');
console.log(cat, cat.say());
if (cat.say() === "I'm a white cat" && cat instanceof Cat && cat instanceof Animal) {
console.log('success');
}
// Animal { name: 'cat', color: 'white' } I'm a white cat
// success5、函数柯里化
js
// 柯里化求和函数
var add = function () {
var _args = [];
return function () {
if (arguments.length === 0) {
return _args.reduce(function (a, b) {
return a + b;
});
}
[].push.apply(_args, arguments);
return arguments.callee;
};
};
var sum = add();
sum(100, 200)(300);
sum(400);
console.log(sum(500)(5000)()); // 1000
//通用柯里化函数
var curry = function (fn) {
var len = fn.length,
args = [];
return function () {
Array.prototype.push.apply(args, arguments);
var argsLen = args.length;
if (argsLen < len) {
return arguments.callee;
}
return fn.apply(fn, args);
};
};
var add = function (a, b, c) {
return a + b + c;
};
var mult = function (a, b, c) {
return a * b * c;
};
var adder = curry(add);
console.log(adder(1)(2)(3));
var multer = curry(mult);
console.log(multer(2)(5)(10));6、防抖节流
js
/**
* 防抖
* @param {Function} fn
* @param {Number} time
*/
function debounce(fn, time) {
let timeout = null;
return (...args) => {
clearTimeout(timeout);
timeout = setTimeout(() => {
fn.apply(this, args);
}, time);
};
}
/**
* 节流
* @param {*} fn
* @param {*} delay
*/
function throttle(fn, delay) {
let prevTime = Date.now();
return (...args) => {
let curTime = Date.now();
if (curTime - prevTime > delay) {
fn.apply(this, args);
prevTime = curTime;
}
};
}7、 promise.all
js
/**
* 1、判断入参是否合法
* 2. 函数返回值为 `<Promise>` 对象, 当参数 `promises` 内所有的 `Promise` 成功,
* 该 `<Promise>` 对象成功, 成功,数据为所有成功的 `Promise` 结果数组。
* 有一个不成功, 则该 `<Promise>` 不成功, 失败数据为失败原因
*/
Promise._all = (promises) => {
// 该方法返回一个promise对象
return new Promise((resolve, reject) => {
// 该方法的参数需为一个可迭代对象
if (promises === null || typeof promises[Symbol.iterator] !== 'function') {
throw new TypeError(`${promises} is not a iterable`);
}
promises = [...promises];
// 可迭代对象为空则 resolve 一个 []
if (promises.length === 0) {
resolve([]);
}
let result = [];
let count = 0;
promises.forEach((promise, index) => {
Promise.resolve(promise)
.then((res) => {
result[index] = res;
count++;
if (count === promises.length) {
resolve(result);
}
})
.catch((err) => {
reject(err);
});
});
});
};
// 验证
function testPromise() {
try {
Promise._all(null).then(
(res) => console.log(res),
(rej) => console.log(rej)
);
// throw err: null is not iterable
} catch (e) {
console.log(e);
}
try {
Promise._all({}).then(
(res) => console.log(res),
(rej) => console.log(rej)
);
// throw err: [object object] is not iterable
} catch (e) {
console.log(e);
}
Promise._all([]).then(
(res) => console.log(res),
(rej) => console.log(rej)
);
// []
Promise._all(new Set()).then(
(res) => console.log(res),
(rej) => console.log(rej)
);
// []
Promise._all(new Map()).then(
(res) => console.log(res),
(rej) => console.log(rej)
);
// []
Promise._all([Promise.resolve(1), Promise.resolve(2), Promise.resolve(3), 4]).then(
(res) => console.log(res),
(rej) => console.log(rej)
);
// [1, 2, 3, 4]
Promise._all([Promise.reject(1), Promise.resolve(2), Promise.resolve(3), 4]).then(
(res) => console.log(res),
(rej) => console.log(rej)
);
// 1
}
testPromise();
russ