回复
前端面试系列-JavaScript-call、applay、bind的区别及代码实现
开发者训练营官方
发布于 2021-3-25 17:01
浏览
0收藏
call 和 apply 的主要作用,是改变对象的执行上下文,并且是立即执行的。它们在参数上的写法略有区别;bind 也能改变对象的执行上下文,它与 call 和 apply 不同的是,返回值是一个函数,并且需要稍后再调用一下,才会执行。
一、call
call 的写法
Function.call(obj,[param1[,param2[,…[,paramN]]]])
var name = 'name'
var obj = {
name: 'objName'
}
function getName(p1, p2) {
console.log(p1, p2,this.name)
}
getName(1, 2) //1 2 "name"
getName.call(obj, 1, 2)//1 2 "objName"
需要注意以下几点:
- 调用 call 的对象,必须是个函数 Function。
- call 的第一个参数,是一个对象。 Function 的调用者,将会指向这个对象。如果不传,则默认为全局对象 window。
- 第二个参数开始,可以接收任意个参数。每个参数会映射到相应位置的 Function 的参数上。但是如果将所有的参数作为数组传入,它们会作为一个整体映射到 Function 对应的第一个参数上,之后参数都为空。
function func (a,b,c) {} func.call(obj, 1,2,3) // func 接收到的参数实际上是 1,2,3 func.call(obj, [1,2,3]) // func 接收到的参数实际上是 [1,2,3],undefined,undefined
call模拟实现 - 明确是谁调用call:函数。
- call接收的第一个参数是要改变的this指向(去执行这个函数)。若无指定,默认为window
- call接收的后续参数就是作为调用call的那个函数所需的参数。
function myCall(context) { //判断一下 if (typeof this !== 'function'){ throw new TypeError('error') } //this指向,谁去执行去这个函数 context = context || window //要执行的函数 context.fn = this //取出参数 const args = [...arguments].slice(1) //执行函数 const result = context.fn(...args) //删除fn delete context.fn return result }
验证一下
Function.prototype.myCall = myCall
getName.myCall(obj, 1, 2)//1 2 "objName"
二、applay
apply使用与call大体一致,只是接受参数的方法不同。call可以接收多个参数。apply接收的第一个参数是this,第二个参数是 所需参数所组成的数组。
Function.apply(obj[,argArray])
applay模拟实现
function myApply(context) {
if (typeof this !== 'function') {
throw new TypeError('Error');
}
context = context || window;
context.fn = this;
var result;
if (arguments[1]) {
result = context.fn(...arguments[1]);
} else {
result = context.fn();
}
delete context.fn;
return result;
}
三、bind
Function.bind(thisArg[, arg1[, arg2[, ...]]])
bind 方法 与 apply 和 call 比较类似,也能改变函数体内的 this 指向。不同的是,bind 方法的返回值是函数,并且需要稍后调用,才会执行。而 apply 和 call 则是立即调用。
bind模拟实现
function myBind(context) {
if (typeof this !== 'function') {
throw new TypeError('Error')
}
const _this = this
const args = [...arguments].slice(1)
// 返回函数
return function F() {
// 1 判断是否用作构造函数
if (this instanceof F) {
return new _this(...args, ...arguments)
}
// 2 用作普通函数
return _this.apply(context, args.concat(...arguments))
}
}
验证一下:
普通函数
Function.prototype.myBind = myBind
var name = 'name'
var obj = {
name: 'objName'
}
function test(p1, p2){
this.a = p1
this.b = p2
console.log(this.name,p1, p2)
}
var f1 = test.myBind(obj, 1)
f1(2)//objName 1 2
构造函数
var name = 'name'
var obj = {
name: 'objName'
}
function test(p1, p2){
this.a = p1
this.b = p2
console.log(this.name,p1, p2)//undefined 1 2
}
var f1 = test.myBind(obj, 1)
var f= new f1(2)
console.log(f)//test {a: 1, b: 2}
应用场景
1.对象的继承
function superClass () {
this.value = 123;
this.print = function () {
console.log(this.value);
}
}
function subClass () {
superClass.call(this);
this.print();
}
subClass();
//123
2.借用方法
使类数组可以使用Array 原型链上的方法
let domNodes = Array.prototype.slice.call(document.getElementsByTagName("*"));
3.Math.max||Math.min
let arr = [1,2,3,4,5];
console.log(Math.max.apply(this,arr))//5
console.log(Math.min.call(this,...arr))//1
4.数组合并
let arr1 = [1, 2, 3];
let arr2 = [4, 5, 6];
Array.prototype.push.apply(arr1, arr2);
console.log(arr1); // [1, 2, 3, 4, 5, 6]
————————————————
版权声明:本文为博主「LYFlied」的原创文章
分类
赞
收藏
回复
相关推荐