区别
相同点都可以改变函数内部this的指向
不同点:call、apply传递的参数不同,bind返回一个修改this指向的新函数
call
call 方法第一个参数是要绑定给this的值,后面传入的是一个参数列表。当第一个参数为null、undefined的时候,默认指向window。
function fn(m,n){
console.log(this,m,n)
}
fn.call({a:1},1,2) //{a:1} 1 2
apply
apply接受两个参数,第一个参数是要绑定给this的值,第二个参数是一个参数数组。当第一个参数为null、undefined的时候,默认指向window。
function fn(m,n){
console.log(this,m,n)
}
fn.apply({a:1},[1,2]) //{a:1} 1 2
事实上apply 和 call 的用法几乎相同, 唯一的差别在于:当函数需要传递多个变量时, apply 可以接受一个数组作为参数输入, call 则是接受一系列的单独变量。
bind
bind返回一个修改this指向的新函数,并且只能bind一次
function fn(m,n,x,y){
console.log(this,m,n,x,y)
}
let fn1 = fn.bind({a:1},1,2);
fn1(3,4) //{a:1} 1 2 3 4
应用
1、最大最小值
Math.max(1,2,3) // 3
Math.min(1,2,3) // 1
let arr = [1,2,3]
Math.max.apply(null,arr) // 3
// 当然也可以es6中的扩展运算符
Math.max(...arr) // 3
2、类数组转数组
let divs = document.querySelector("div")
Array.prototype.slice.call(divs)
Array.from(divs)
[...divs]
3、数组追加元素
let arr = [1,2,3]
let arr1 = [4,5,6]
Array.prototype.push.apply(arr,arr1)
4、精准判断数据类型
let a1 = 1, a2 = "1", a3 = true, a4 = undefined, a5 = null, a6 = [], a7 = {}, a8 = function(){}
Object.prototype.toString.call(a1) // "[object Number]"
Object.prototype.toString.call(a2) // "[object String]"
Object.prototype.toString.call(a3) // "[object Boolean]"
Object.prototype.toString.call(a4) // "[object Undefined]"
Object.prototype.toString.call(a5) // "[object Null]"
Object.prototype.toString.call(a6) // "[object Array]"
Object.prototype.toString.call(a7) // "[object Object]"
Object.prototype.toString.call(a8) // "[object Function]"
5、原型继承
function Person(name, age){
this.name = name
this.age = age
}
function People(name, age){
Person.call(this, name, age)
}
let people = new People("zhangSan", 25)
底层实现
Function.prototype.bind = function(context,...arg) {
if (typeof this !== 'function') {
throw new TypeError('Error')
}
let _this = this;
context = context == undefined ? window : context;
let type = typeof context;
if (!/^(object|function)$/.test(type)) {
if (/^(symbol|bigint)$/.test(type)) {
context = Object(context);
} else {
context = new context.constructor(context);
}
}
return function anonymous(...arg1){
_this.call(context,...arg,...arg1)
}
};
Function.prototype.call = function(context,...arg) {
// console.log(arg)
if (typeof this !== 'function') {
throw new TypeError('Error')
}
context = context == undefined ? window : context;
let type = typeof context;
if(!/^(object|fucntion)$/.test(type)){
if(/^(symbol|bigint)$/.test(type)){
context = Object(context)
}else{
context = new context.constructor(context)
}
}
let key = Symbol('key'),
result;
context[key] = this;
result = context[key](...arg)
delete context[key]
return result
}
Function.prototype.apply = function(context,arg) {
// console.log(arg)
if (typeof this !== 'function') {
throw new TypeError('Error')
}
context = context == undefined ? window : context;
let type = typeof context;
if(!/^(object|fucntion)$/.test(type)){
if(/^(symbol|bigint)$/.test(type)){
context = Object(context)
}else{
context = new context.constructor(context)
}
}
let key = Symbol('key'),
result;
context[key] = this;
// 处理参数和 call 有区别
if (arg) {
result = context[key](...arg)
} else {
result = context[key]()
}
delete context[key]
return result
}
以上就是对这三个函数的一些总结了,好了,今天就到这里了,剩下的,同学你来吧!