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>
## apply
1. apply 会立即调用函数
2. 第一个参数是指定对象,传参是以数组的方式
3. 如果第一个参数传入 undefined、null 会指向window
```javascript
Function.prototype.myApply = function (thisArg, arrArg) {
const fn = this
thisArg = (thisArg !== undefined && thisArg != null) ? Object(thisArg) : window
thisArg.fn = fn
arrArg = arrArg || []
const res = thisArg.fn(...arrArg)
delete thisArg.fn
return 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 = fn
const res = thisArg.fn(...arrArgs, ...args)
delete thisArg.fn
return 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秒内再次执行则重新计时
```javascript
function debounce(fn, delay) {
let timer = null
return function (...args) {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, args)
timer = null
}, delay)
}
}
节流
节流:事件频繁触发的过程中,在n秒内只触发一次,不管n秒内触发多少次
//定时器
function throttle(fn, delay) {
let timer = null
return function (...args) {
if (timer) return
timer = setTimeout(() => {
fn.apply(this, args)
timer = null
}, delay)
}
}
// 时间戳
function throttle(fn, delay) {
let last = 0
return function (...args) {
const now = Date.now()
if (now - last > delay) {
last = now
fn.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 true
proto = Object.getPrototypeOf(proto)
}
return false
}
4、new
new执行过程
- 创建一个新对象
- 将这个对象的原型proto指向构造函数的原型对象prototype
- 构造函数的this指向这个对象,并执行构造函数中的代码
- 返回新对象(判断构造函数的返回值:如果返回值是对象则返回这个对象,否则返回这个新对象)
function Foo(){
const obj = {}
obj.__proto__ = Foo.prototype
const 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 = this
let 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 = obj
return 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+concat
const arr2 = arr.reduce((acc, val) => {
return acc.concat(val)
}, [])
// 展开运算符+concat
const 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) return
if(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是不是object
if(typeof target !== null && typeof target !== 'object') {
return target
}
// 解决循环引用
if(map.has(target)) {
return map.get(target)
}
// 判断是object还是array
const 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) return
let left = L, right = R
let 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)
}
}