1、call、apply、bind
实现步骤:
- 将函数设为对象的属性
- 执行该函数
-
call
call 会立即调用函数
- 第一个参数是指定对象,后面的都是传入的参数
如果第一个参数传入 undefined、null 会指向window ```javascript Function.prototype.myCall = function (thisArg, …args) { const fn = this
thisArg = thisArg !== undefined && thisArg !== null ? Object(thisArg) : window
thisArg.fn = fn const result = thisArg.fn(…args) delete thisArg.fn
return result }
// 测试 function sum(num1, num2) { console.log(this) return num1 + num2 }
const res = sum.myCall(‘123’, 20, 30) console.log(res)
<a name="fakof"></a>## apply1. apply 会立即调用函数2. 第一个参数是指定对象,传参是以数组的方式3. 如果第一个参数传入 undefined、null 会指向window```javascriptFunction.prototype.myApply = function (thisArg, arrArg) {const fn = thisthisArg = (thisArg !== undefined && thisArg != null) ? Object(thisArg) : windowthisArg.fn = fnarrArg = arrArg || []const res = thisArg.fn(...arrArg)delete thisArg.fnreturn res}// 测试function sum(num1, num2) {return num1 + num2}const res = sum.myApply("123", [20, 30])console.log(res);
bind
- 不会立即调用函数,会返回一个变更后的函数
- 第一个参数是指定对象,后面的都是传入的参数
- 如果第一个参数传入 undefined、null 会指向window
可以分开传参,const foo = bind(this,1,2);foo(3,4) ```javascript Function.prototype.myBind = function (thisArg, …arrArgs) { const fn = this thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window
function proxyFn(…args) {
thisArg.fn = fnconst res = thisArg.fn(...arrArgs, ...args)delete thisArg.fnreturn res
}
return proxyFn
}
// 测试 function foo(num1, num2) { console.log(this); console.log(num1, num2); return num1 + num2 }
// foo.myBind(“123”, 10, 20)
const bar = foo.myBind(“123”, 10, 20) console.log(bar());
<a name="GP9Yo"></a># 2、防抖、节流<a name="IAtF1"></a>## 防抖防抖:事件频繁触发后的n秒内只执行一次,若n秒内再次执行则重新计时```javascriptfunction debounce(fn, delay) {let timer = nullreturn function (...args) {if (timer) clearTimeout(timer)timer = setTimeout(() => {fn.apply(this, args)timer = null}, delay)}}
节流
节流:事件频繁触发的过程中,在n秒内只触发一次,不管n秒内触发多少次
//定时器function throttle(fn, delay) {let timer = nullreturn function (...args) {if (timer) returntimer = setTimeout(() => {fn.apply(this, args)timer = null}, delay)}}// 时间戳function throttle(fn, delay) {let last = 0return function (...args) {const now = Date.now()if (now - last > delay) {last = nowfn.apply(this, args)}}}
3、instanceof
instanceof:判断其构造函数的prototype属性是否在该实例对象的原型链上
function myInstanceof(target, origin) {if(target === null || (typeof target !== 'object' && typeof target !== 'function')) {return false}if(typeof origin !== 'funtion') throw new Error('origin typeError')let proto = Object.getPrototypeOf(target) // proto = target.__proto__while (proto) {if (proto === origin.prototype) return trueproto = Object.getPrototypeOf(proto)}return false}
4、new
new执行过程
- 创建一个新对象
- 将这个对象的原型proto指向构造函数的原型对象prototype
- 构造函数的this指向这个对象,并执行构造函数中的代码
- 返回新对象(判断构造函数的返回值:如果返回值是对象则返回这个对象,否则返回这个新对象)
function Foo(){const obj = {}obj.__proto__ = Foo.prototypeconst res = Foo.call(obj)return typeof res === 'object' ? res : obj}
5、去重
set
function unique(arr){return [...new Set(arr)]}
filter
function unique(arr){return arr.filter((item, index, arr) => {return arr.indexOf(item) === index})}
6、reduce
Array.prototype.myReduce = function(cb, initValue){const arr = thislet total = initValue || arr[0]for(let i = initValue ? 0 : 1; i < arr.length; i++){total = cb(total, arr[i], i, arr)}return total}
7、Object.create()
原理:传入的对象作为新对象的原型Object.myCreate = function(obj){function Foo(){}Foo.prototype = objreturn new Foo()}
8、数组扁平化
数组扁平化也就是数组降维
展开一层
const arr = [1, 2, [3, 4, [5, 6]]]// ES6 Array.prototype.flat() 该参数为depth为降维的深度const arr1 = arr.flat() // [ 1, 2, 3, 4, [ 5, 6 ] ]// reduce+concatconst arr2 = arr.reduce((acc, val) => {return acc.concat(val)}, [])// 展开运算符+concatconst arr3 = [].concat(...arr)
展开多层
const arr = [1, 2, [3, 4, [5, 6]]]// ES6 Array.prototype.flat()const arr4 = arr.flat(Infinity) // [ 1, 2, 3, 4, 5, 6 ]// 递归调用function flatDeep(arr, depth = 1) {return depth > 0? arr.reduce((acc, val) => {return acc.concat(Array.isArray(val) ? flatDeep(val, depth - 1) : val)}, []): arr.concat()}// 堆栈function flatten(arr) {const stack = [...arr]const res = []while (stack.length) {const next = stack.pop()if (Array.isArray(next)) {stack.push(...next)} else {res.push(next)}}return res.reverse()}
9、Generator自执行函数
Generator 函数的自动执行需要一种机制,即当异步操作有了结果,能够自动交回执行权
- 回调函数。将异步操作进行包装,暴露出回调函数,在回调函数里面交回执行权
- Promise 对象。将异步操作包装成 Promise 对象,用 then 方法交回执行权
function run(gen){const g = gen()function next(data){const result = g.next(data)if(result.done) returnif(typeof result.value.then === 'function') {result.value.then(function(data){next(data)})} else {result.value(next)}}next()}
10、深拷贝
深拷贝:拷贝对象时不会拷贝引用,修改原对象的属性不会影响拷贝对象
function deepClone(target, map = new WeakMap()) {// 判断target是不是objectif(typeof target !== null && typeof target !== 'object') {return target}// 解决循环引用if(map.has(target)) {return map.get(target)}// 判断是object还是arrayconst newObject = Array.isArray(target) ? [] : {}map.set(target, newObject)for(const key in target) {newObject[key] = deepClone(target[key], map)}return newObject}
11、浅拷贝
浅拷贝:拷贝对象时会拷贝引用,修改原对象的属性会影响拷贝对象
// 方式一:展开运算符const obj1 = { ...obj }// 方式二:利用Object.assign()进行浅拷贝const obj2 = Object.assign({}, obj)// 在数组中利用 Array.prototype.concat() 进行浅拷贝const arr = [].concat(arr)
12、EventBus(事件总线)
13、函数柯里化
柯里化:就是将函数内大量的逻辑分到一个个小函数中处理 柯里化优势:
- 确保了单一职责的原则,每个函数的职责清晰明了
- 对代码逻辑的复用,对确定的函数无需多次调用
自动柯里化:将一个普通函数,自动转化为柯里化函数
function myCurrying(fn) {// 判断当前已经接收的参数的个数,与参数本身需要接收的参数是否一致// 1.当已经传入的参数 大于等于 需要的参数时,就执行函数return function curried(...args) {if (args.length >= fn.length) {// 用apply的原因是防止在外界显示绑定了对象,与外界保持一致return fn.apply(this, args)} else {// 没有达到个数时,需要返回一个新的函数,继续接收所需参数return function (...args2) {// 接收到参数时 递归调用 继续判断参数是否满足return curried.apply(this, [...args, ...args2])}}}}
14、组合函数
15、实现继承
16、排序算法
快速排序
function quickSort(arr, L, R) {if(L > R) returnlet left = L, right = Rlet point = arr[left]while(left < right) {while(left < right && arr[right] >= point) {right--}if(left < right) {arr[left] = arr[right]}while(left < right && arr[left] <= point) {left++}if(left < right) {arr[right] = arr[left]}if(left >= right) {arr[left] = point}quickSort(arr, L, left-1)quickSort(arr, left+1, R)}}
