没有生而知之,只有学而知之。多练习,多总结。给自己打打气,坚持学习,加油!欢迎大家留言补充。
实现 call
Function.prototype.myCall = function (context) {
const args = [...arguments].slice(1);
//使用一个对象属性模拟
const obj = context || window;
const fn = Symbol("fn");
obj[fn] = this;
const res = obj[fn](...args);
delete obj[fn];
return res;
}
实现 apply
//同 call 不同的是第二个参数必须是数组
Function.prototype.myApply = function (context, args = []) {
const obj = context || window;
const fn = Symbol("fn");
obj[fn] = this;
const res = obj[fn](...args);
delete obj[fn];
return res;
}
实现 bind
Function.prototype.myBind = function (context, ...outerArgs) {
let fn = this;
function res(...innerArgs) {
if (this instanceof res) {
// new操作符执行时
fn.call(this, ...outerArgs, ...innerArgs)
} else {
// 普通bind
fn.call(context, ...outerArgs, ...innerArgs)
}
}
res.prototype = this.prototype;
return res
}
var foo = {
name: "foo",
say: function () {
console.log(this.name);
}
}
foo.say.myBind({name: "William"})();
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.toString = function () {
return `${this.x}, ${this.y}`
}
const YAxisPoint = Point.myBind(null, 0);
const tmp = new YAxisPoint(5);
console.log(tmp);
console.log(tmp instanceof YAxisPoint, tmp instanceof Point);
发布订阅
class EventHub{
cache = {};
//订阅
add(eventName, fn){
this.cache[eventName] = this.cache[eventName] || [];
this.cache[eventName].push(fn);
}
//取消订阅
off(eventName, fn){
const fns = this.cache[eventName] || [];
const index = fns.indexOf(fn);
if(index>=0){
this.cache[eventName].splice(index, 1);
}
}
//发布
emit(eventName, data){
const fns = this.cache[eventName] || [];
for(let fn of fns){
fn(data);
}
}
}
实现 new
function create(fn, ...rest) {
//相当于 let obj.__proto__ = fn.prototype;
let obj = Object.create(fn.prototype);
let result = fn.apply(obj, rest);
if (typeof result === 'object') {
return result;
} else {
return obj;
}
}
Object.create 的基本实现原理
//方式一
function create(obj){
function F(){}
F.prototype = obj;
return new F();
}
// 方式二
function create(obj){
const m = {};
m.__proto__ = obj;
return m;
}
实现 instanceof
function myInstanceof(f, F) {
let flag = false;
while (!flag && f.__proto__) {
flag = f.__proto__ === F.prototype;
f = f.__proto__;
}
return flag;
}
实现 Array.isArray 实现
Array.myIsArray = function(arr){
return Object.prototype.toString.call(arr)==="[object Array]";
}
实现继承
function Shape(type){
this.type = type;
}
Shape.prototype.draw = function(){
console.log(this.type);
}
function Circle(type, color){
//执行父级构造函数
Shape.call(this, type);
this.color = color;
}
//继承原型方法
Circle.prototype = Object.create(Shape.prototype);
//属性 constructor 指向本来的构造函数
Circle.prototype.constructor = Circle;
let c = new Circle("circle", "red");
c.draw();
实现节流和防抖
//节流
function throttle(fn, delay) {
let timer;
return function () {
if (!timer) {
timer = setTimeout(() => {
fn();
timer = null;
}, delay)
}
}
}
//防抖
function debounce(fn, delay){
let timer;
return function(){
if(timer){
clearTimeout(timer);
}
timer = setTimeout(()=>{
fn();
}, delay);
}
}
实现对象(数组)深拷贝
不考虑循环引用
function deepCopy(obj) {
let res;
if (typeof obj === "object") {
if (Array.isArray(obj)) {
res = [];
} else {
res = {};
}
for (let key in obj) {
const tmp = obj[key];
if (typeof tmp === "object") {
res[key] = deepCopy(tmp);
} else {
res[key] = tmp;
}
}
return res;
} else {
return obj;
}
}
考虑循环引用
上面的代码如果是循环引用对象的话,会出现 Uncaught RangeError: Maximum call stack size exceeded
递归次数过多,没有正确的退出递归造成堆栈溢出。
function deepCopy(obj, uniqueList = []) {
let res;
if (typeof obj === "object") {
res = Array.isArray(obj) ? [] : {};
//记录所有需要递归调用的 key 和 value,避免一直循环
const uniqueDate = find(uniqueList, obj);
if (uniqueDate) {
return uniqueDate.target;
}
uniqueList.push({
source: obj,
target: res
});
for (let key in obj) {
const tmp = obj[key];
if (typeof tmp === "object") {
res[key] = deepCopy(tmp, uniqueList);
} else {
res[key] = tmp;
}
}
console.log(uniqueList);
return res;
} else {
return obj;
}
}
function find(arr, item) {
for (let a of arr) {
if (a.source === item) {
return a;
}
}
return null;
}
实现 reduce
Array.prototype.myReduce = function (fn, init=null) {
const arr = this;
if(arr.length===0){
return init;
}
let result = null;
let index = 0;
if(!init){
init = arr[index];
index++;
}
while(index < arr.length){
if(!arr.hasOwnProperty(index)){
index++;
continue;
}
const tmp = arr[index];
result = fn(init, tmp);
init = result;
index++;
}
return result;
}
sum(1)(1,2,3)(1)
function sum(){
let _args = [...arguments];
const _add = function(){
_args = _args.concat(...arguments);
return _add;
}
_add.toString = function(){
return _args.reduce((cal, cur)=>cal+cur);
}
return _add();
}
函数柯里化实现
const curry = function(fn){
let args=[];
const inner = function(){
args = args.concat(...arguments);
if(args.length === fn.length){
return fn(...args);
}else{
return inner;
}
}
return inner;
}
const sum = (a, b, c, d) => a + b + c + d;
const currySum = curry(sum);
console.log(currySum(1)(2)(3)(4));
斐波那契数列优化后
function fabo(n){
if(n===1||n===2){
return 1;
}
let a = 1;
let b = 1;
for(let i=3;i<=n;i++){
let tmp = a;
a = b;
b = a + tmp;
}
return b;
}
具体优化过程: juejin.cn/post/691606…
实现 Promise
实现 async & await
主要是利用 Generator 函数实现。使用 async & await 的例子:
const getData = () => new Promise(resolve => setTimeout(() => resolve("data"), 1000))
async function test() {
const data = await getData()
console.log('data: ', data);
const data2 = await getData()
console.log('data2: ', data2);
return 'success'
}
// 这样的一个函数 应该再1秒后打印data 再过一秒打印data2 最后打印success
test().then(res => console.log(res))
作者:ssh_晨曦时梦见兮
链接:https://juejin.cn/post/6844904102053281806
async
标志的函数会返回一个 Promise
对象,并且 await
执行的结果是 .then
里面的结果。这两点是 Generator 函数没有实现的。所以,我们使用Generator 函数模拟的时候要实现上面 2 个能力。 对于第一个问题,我们可以封装一个 asyncToGenerator 函数执行 test,让其返回 Promise 对象;对于第二个问题,使用 next(val)
将结果返回出去。
const getData = () => new Promise(resolve => setTimeout(() => resolve("data"), 1000));
function* test() {
const data = yield getData();
console.log('data: ', data);
const data2 = yield getData();
console.log('data2: ', data2);
return 'success'
}
//模拟
function asyncToGenerator(generatorFunc) {
const func = generatorFunc();
return new Promise((resolve, reject) => {
let g = func.next();
function step(){
const {done, value} = g;
if(done){
resolve(value);
}else{
return Promise.resolve(value).then(res=>{
g = func.next(res);
step();
})
}
}
step();
})
}
asyncToGenerator(test).then(res=>{
console.log("finish", res)
})
排序
冒泡排序
function dubbleSort(arr) {
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
let tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
}
时间复杂度:O(n^2)
快速排序
function quickSort(arr){
if(arr.length==0){
return [];
}
const pirot = arr.pop();
const left = [];
const right = [];
for(let m of arr){
if(m>pirot){
left.push(m);
}else{
right.push(m);
}
}
return quickSort(right).concat(pirot, quickSort(left))
}
时间复杂度:O(nlog2n)
查找
二分查找
function binarySearch(arr, target) {
if (arr.length === 0) {
return -1;
}
let left = 0;
let right = arr.length - 1; // [left, right]
while (left <= right) {
const middle = left + parseInt((right - left) / 2);
const tmp = arr[middle];
if (tmp === target) {
return middle;
} else if (tmp > target) {
right = middle - 1;
} else {
left = middle + 1;
}
}
return -1;
}
JS异步调度器
class Scheduler {
constructor(maxNum=2) {
this.queue = [];
this.count = 0;
this.maxNum = maxNum;
}
add(promiseCreator) {
this.count++;
if (this.count <= this.maxNum) {
return promiseCreator().then(res => {
this.exc();
})
} else {
return new Promise((resolve, reject) => {
this.queue.push([promiseCreator, resolve]);
})
}
}
exc() {
if (this.queue.length > 0) {
const [fn, resolve] = this.queue.shift();
fn().then(res=>{
resolve();
this.exc();
})
}
}
}
const scheduler = new Scheduler()
const timeout = (time) => {
return new Promise(r => setTimeout(r, time))
}
const start = new Date().getTime();
const addTask = (time, order) => {
scheduler.add(() => timeout(time))
.then(() => console.log(order, new Date().getTime() - start))
}
addTask(1000, 1)
addTask(500, 2)
addTask(300, 3)
addTask(400, 4)
addTask(400, 5)
最后
如果有错误或者不严谨的地方,烦请给予指正,十分感谢。如果喜欢或者有所启发,欢迎点赞,对作者也是一种鼓励。