手写bind方法
要说到bind方法,自然离不开说到他的两个兄弟call和apply了。他们三兄弟最主要的功能就是改变this的指向了,也就是改变对象的执行上下文,但彼此之间也有一些不同。
下面就细细道来~
call方法
call 的语法:
Function.call (obj,[param1...])
- 调用 call 的对象,必须是个函数。
- call 的第一个参数,是一个对象。 Function 的调用者,将会指向这个对象。如果不传,则默认为全局对象 window。
- 第二个参数开始,可以接收任意个参数。每个参数会映射到相应位置的 Function 的参数上。但是如果将所有的参数作为数组传入,它们会作为一个整体映射到 Function 对应的第一个参数上,之后参数都为空。
- 执行完 call 会立即执行函数
一个小例子:
function fn1() {
console.log(this)
}
fn1() // window
fn1.call({ x: 100 }) // {x:100}
// 不但会绑定this还会执行fn1函数
apply方法
apply 的语法:
Function.apply(obj,[,argArray])
- 调用 apply 的对象,必须是个函数。
-
第二个参数,必须是数组或者类数组,它们会被转换成类数组,传入 Function 中,并且会被映射到 Function 对应的参数上。
这也是 call 和 apply 之间,很重要的一个区别。
- 执行完 apply 方法会立即执行函数
call和apply的用途
1.ES6 之前可以用来继承
2.计算最大最小值
let max = Math.max.apply(null, array);
let min = Math.min.apply(null, array);
bind方法
bind 的语法:
Function.bind(obj,[param1...])
bind方法和其他两兄弟基本相同,
除了
执行完不会立马执行。
一个小例子
function fn1(a, b, c) {
console.log('this', this); // this {x: 100}
console.log(a, b, c); //10 20 30
return 'this is fn1'
}
const fn2 = fn1.bind({ x: 100 }, 10, 20, 30)
const res = fn2()
console.log(res); //this is fn1
手写bind方法
区分完三兄弟之后,开始手写bind方法,也是面试中经常会考到的手写代码啦
// 手写bind方法,即写一个自己的插件
// 由于原生bind方法的参数个数不一定(即除了绑定this的参数外,还有其他可能传入的参数)
Function.prototype.bind1 = function () {
// 将参数拆解为数组
const args = Array.prototype.slice.call(arguments, 0);
// Array.prototype.slice.call(arguments)能将有length属性的对象转换为数组
// 前提:arguments是一个具有length属性的对象
// call 方法改变this指向
// Array.prototype.slice 改变了 slice 只能操作对象的情况,并转化为数组
// 最后返回一个数组
//获取this(数组第一项)
const t = args.shift();
// shift方法是将数组的第一项去除并且返回剩余的内容作为新的数组
// const a = [1, 2, 3, 4]
// a.shift() // 1
// console.log(a);//[2,3,4]
//fn1.bind(...)中的fn1
const self = this;
//返回一个函数
return function () {
return self.apply(t, args);
}
}
再结合刚才的例子
function fn1(a, b, c) {
console.log('this', this); // this {x: 100}
console.log(a, b, c); //10 20 30
return 'this is fn1'
}
const fn2 = fn1.bind1({ x: 100 }, 10, 20, 30)
const res = fn2()
console.log(res); //this is fn1
手写深拷贝
深拷贝出现的原因就是在普通的拷贝(浅拷贝)下,对引用类型的数据会出现拷贝失败,因为只拷贝了引用数据,未拷贝地址。因此会出现更改数值两个对象都改变的情况,所以深拷贝的重要性不言而喻~
const obj1 = {
age: 20,
name: 'xxx',
address: {
city: 'beijing'
},
arr: ['a', 'b', 'c'],
};
/**
* 深拷贝
* @param {Object} obj 要拷贝的对象
*/
function deepClone(obj = {}) {
if (typeof obj !== 'object' || obj == null) {
// obj 是null,或者不是对象和数组,直接返回
return obj;
}
// 初始化返回结果
let result
if (obj instanceof Array) {
result = [];
} else {
result = {};
};
for (let key in obj) {
// 保证 key 不是原型的属性
if (obj.hasOwnProperty(key)) {
// 递归调用
result[key] = deepClone(obj[key]);
};
};
// 返回结果
return result
}
// 深拷贝
const obj2 = deepClone(obj1);
// 浅拷贝
// const obj2 = obj1;
obj2.address.city = 'wuhan'
console.log(obj1.address.city);
// 深拷贝结果为beijing,正确, 因为obj2改变不影响obj1的内容
// 浅拷贝结果为wuhan,错误,obj2的改变影响了obj1的内容
除了这种源码形式的深拷贝,还有两种形式:
- JSON.parse(JSON.stringify(obj))
- 使用 lodash 工具
版权声明:本文为weixin_44738381原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。