每个function都是Function的实例,都可以调用其原型上的三个方法
- Funtion.prototype(apply,call,bind)
call
call方法执行的作用是:把fn执行,并把fn中的this指向变为我们传递的第一个实参obj
function fn(x,y){
console.log(this.name)
}
let obj = {
name:"obj"
}
fn.call(obj)
// fn首先基于__proto__找到Function.prototype上的call方法,执行call方法
- 传递的实参obj
- call方法中的this -> fn
- fn.call(obj,10,20,30,...) call第二个第三个参数传给fn作为参数
- fn.call(10,20,30) this->10 this指向10 其余成为实参
- fn.call() this->window 指向window
apply
与call只有一个区别:传递给执行函数的实参方式不一样,参数越多,call性能越好
fn.call(obj,10,20,30,...)
fn.apply(obj,[10,20,30,...])
最后结果一样
let arr = [10,20]
fn.apply(obj,arr)
fn.apply(obj,...arr)
call、apply 实际应用
1. **数组排序 取最大值**
let arr = [1,7,89,45,67,3,2]
arr.sort((a,b)=>b-a) arr[0]
console.log(Math.max(...arr))
console.log(Math.max.apply(Math,arr))
let str = 'Math.max('+ arr + ')'
console.log(eval(str))
2. **鸭子类型(把长得像鸭子的,称它为鸭子,最主要的是让其具有鸭子的特点)**
function fn(){
console.log(arguments)
// 类数组对象,不能直接使用数组的方 arguments.__proto = Object.prototype
// 想让类数组拥有数组的方法(Array.prototype)
// 方案1:把类数组变成数组
let arr = [...arguments]
let arr = Array.from(arguments)
ler arr=[]
for(let i = 0 ; i < arguments.length;i++){
arr.push(arguments[i])
}
// Array.prototype.slice = function slice(){ //数组浅克隆
// for(let i =0;i < this.length ; i++){
// arr.push(this[i])
// }
// return arr
//}
//上面的方法等同于 let arr =Array.prototype.slice.call(arguments,0)
let arr =[].slice.call(arguments,0)
//参考下方图片 大多数数组方法都可以参照此方式给类数组
//[].prototype.foreach.call(arguments,item=>{
// console.log(item)
// })
方案2:直接借用
return [].reduce.call(arguments,(total,item)=>total+item)
方案3:改变原型指向
arguments.__proto__ = Array.prototype
return arguments.reduce((total,item)=>total+item)
console.log(arr)
let obj = {
a:1,
b:2,
4:3,
length:2,
push:Array.prototype.push
}
obj.push(1)
}
fn(10,20,30,40)
bind
** call/apply都是立即把函数执行「改变this和传入参数」,
** bind没有把函数立即执行,而是预先把后期要改变的this和参数存储起来「柯理化」
**
function fn(x,y,ev){
console.log(this,x,y,ev)
return x+y
}
let obj = {
name:"obj"
}
//执行bind会返回一个新函数「预先把fn/obj/10/20存储起来」,fn没有立即执行
let proxy = fn.bind(obj,10,20)
//执行proxy,内部会帮我们执行fn,「this和obj都已经处理过了」,
proxy()
document.onclick = fn;//点击文档才执行fn this->document x->MouseEvent事件对象
y->undefined
document.onclick.call(obj,10,20)// 立即执行 达不到onclick的效果
document.onclick = function(ev){ // 用call也可以实现,过于繁琐
// this->document
fn.call(obj,10,20,ev)
}
document.onclick = fn.bind(obj,10,20) // 可以实现 简单