共计 2568 个字符,预计需要花费 7 分钟才能阅读完成。
本文 github 地址,欢送 star
apply、call、bind 区别
这三个办法都是挂载 Funtion
原型上的办法,所以调用者必须是个函数。
- Function.prototype.call()
- Function.prototype.apply()
- Function.prototype.bind()
这三个函数的应用语法:
func.call(thisArg, param1, param2, ...)
func.apply(thisArg, [param1, param2, ...])
func.bind(thisArg, param1, param2, ...)
他们共有的作用都能够扭转函数运行时 this
的指向。
call
和 apply
的区别在于传递参数的形式不同:
apply
的第2
个参数为数组call
则是从第2
个至第N
个都是给func
的传参
bind
和 call
、apply
的区别在于函数是否立刻执行:
call
、apply
是在扭转了函数的this
指向之后立马执行bind
会返回一个函数,尽管扭转了func
的this
指向,但不是马上执行, 而是调用返回的函数才执行
apply、call、bind 应用场景
获取数组的最值
能够通过 apply
来获取 Math.max()
最大值和 Math.min()
最小值。当然也能够开展来获取数组的最值。
let arr = [1, 2, 3];
const max = Math.max.apply(null, arr); // es6 Math.max(...arr)
const min = Math.min.apply(null, arr); // es6 Math.min(...arr)
console.log(max); // 3
console.log(min); // 1
判断数据类型
能够通过 Object.toString.call
来判断所有的数据类型。
// 判断原生对象
const isPlainObject = val => Object.toString.call(val) === '[object Object]'
// 判断字符串
const isString = val => Object.toString.call(val) === '[object String]'
将类数组转为数组
类数组因为不是真正的数组,所有没有数组类型上自带的种种办法,所以要转为数组,能力调用数组的办法.
let arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};
// ES5 的写法
let arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c']
// ES6 的写法
let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
继承
组合继承应用 call
来实现。
function Parent() {
this.name = '张三';
this.age = 18;
}
Parent3.prototype.getName = function() {return this.name;}
function Child() {Parent3.call(this);
this.address = 'beijing';
}
Child.prototype = new Parent3();
Child.prototype.constructor = Child3;
var s = new Child();
console.log(s.getName()); // '张三'
手写实现
call 的实现
Function.prototype.call = function (context, ...args) {
var context = context || window;
context.fn = this;
var result = eval('context.fn(...args)');
delete context.fn
return result;
}
apply 的实现
apply 和 call 基本原理是差不多的,只是参数存在区。
Function.prototype.apply = function (context, args) {
let context = context || window;
context.fn = this;
let result = eval('context.fn(...args)');
delete context.fn
return result;
}c
bind 的实现
bind
的实现思路根本和 apply
一样,然而在最初实现返回后果这里,bind
和 apply
有着比拟大的差别,bind
不须要间接执行, 须要通过返回一个函数的形式将后果返回,之后再通过执行这个后果,失去想要的执行成果。
Function.prototype.bind = function (context, ...args) {if (typeof this !== "function") {throw new Error("this must be a function");
}
var self = this;
var fbound = function () {self.apply(this instanceof self ? this : context, args.concat(Array.prototype.slice.call(arguments)));
}
if(this.prototype) {fbound.prototype = Object.create(this.prototype);
}
return fbound;
}
bind
须要返回一个函数,然而不能失落函数原型上的属性,因而fbound.prototype = Object.create(this.prototype);
this instanceof self
当这个绑定函数被当做一般函数调用的时候,能够间接用context
;而返回的这个之后当做构造函数应用的时候,却是指向这个实例,所以this instanceof self
为true
时,要用this
。因而这里加了这个判断。
总结
通过上述的剖析,咱们来总结下这三个函数的相同点和不同点,来帮忙更好的了解。
办法 | call | apply | bind |
---|---|---|---|
函数参数 | 一个参数列表 | 一个蕴含多个参数的数组 | 多个参数 |
函数作用 | 扭转函数运行时 this 指向 |
扭转函数运行时 this 指向 |
扭转函数运行时 this 指向 |
返回后果 | 间接执行 | 间接执行 | 期待执行函数 |
底层实现 | 通过eval |
通过eval |
调用apply |
正文完
发表至: javascript
2021-03-21