浅谈call、apply、bind

124 阅读3分钟

要熟悉这三个api,我们首先就要了解this。

this

  1. 在全局执行环境中,无论是否在严格模式下, this 都指向全局对象。
this.w=2
console.log(w);//2
console.log(this===window);//true

这里this就是指全局对象window

  1. 在函数环境中,非严格模式下
function f(){
    console.log(this)
}
f();//window{...}

在调用f函数时,我们可以理解为window.f(),this指的就是window对象

  1. 在函数环境中,严格模式下
function f2(){
  "use strict"; // 这里是严格模式
  console.log(this)
}

f2(); // undefined

这里的this的确应该是undefined,因为f2是被直接调用的,而不是作为对象的属性或方法调用的(如 window.f2())。

4.作为构造器

function Square(width){
    this.width=width
}
Square.prototype.getArea=function(){
    return this.width*this.width
}
Square.prototype.getLength=function(){
    return this.width*4
}
let S=new Square(5)
S.getArea();//25
S.getLength();//20

当this是在new操作符的函数里是时,this就被绑定在这个构造函数的对象(S)上了 5. 直接作为对象

name="Nuna"
let obj={
    name:"Cris",
    age:18,
    fn:function(){
        return this.name
    }
}
obj.fn();//"Cris"
let globalFn=obj.fn
globalFn();//"Nuna"

在上面这个例子中,this===obj,但是,在只拿到fn的value时,function(){ return this.name }就成了全局函数,这时的this就是window,所以得到的是全局变量name

  1. 作为一个内联事件处理函数

当代码被内联on-event 处理函数调用时,它的this指向监听器所在的DOM元素

<button onclick="alert(this.tagName.toLowerCase());">
 Show this
</button>

点击button窗口会弹出"button"

  1. 箭头函数没有this/arguments属性

如果要想把 this 的值从一个环境传到另一个,就要用 call 或者apply 方法。

call

call() 方法使用一个指定的 this >值和单独给出的一个或多个参数来调用一个函数。

语法:function.call(thisArg,arg1,age2,...)

thisArg:在 function 函数运行时使用的 this 值。

arg1, arg2, ...:指定的参数列表。

  1. 在非严格模式下,this 会指向对应类型的包装对象。
function f(){
    console.log(this)
}

f.call() // Window{...}
f.call(null) // Window{...}
f.call(undefined) // Window{...}
f.call(1) // Number{1}
f.call('') // String{""}
f.call(true) // Boolean{true}
f.call({name:"Jane"})//{name: "Jane"}

使用严格模式
function f2() {
    'use strict'
    console.log(this)
}
f2.call()  // undefined
f2.call(undefined)  // undefined
f2.call(null)  // null
f2.call(1)  //1
f2.call('s')//s
f2.call()true//true
f2.call({name:"Jane"})//{name: "Jane"}
  1. 使用 call 方法调用父构造函数
function Fun1(name, age) {
  this.name = name;
  this.age = age;
}

function Fun2(name, age) {
  Fun1.call(this, name, age);
  this.gender = 'man';
}
var result = new Fun2('Cris', 15);
result;  // Fun2{name: "Cris", age: 15, gender: "man"}
  1. 使用 call 方法调用匿名函数
let obj={name:"Jane"};
!function(){
    console.log(this.name)
}.call(obj)

匿名函数后面接.call()会立即调用函数

  1. 使用 call 方法调用函数并且指定上下文的 'this'
function range(){
    let arr=[this.min,'~',this.max].join('')
    console.log(arr)
}
let obj={min:12,max:20}
range.call(obj)  // 12~20

apply

apply()方法的作用和call()方法类似,区别就是call()方法接受的是参数列表,而apply()方法接受的是一个参数数组。

  1. 用 apply 将数组添加到另一个数组
let arr1=[1,2,3]
let arr2=[4,5]
arr1.push.apply(arr1,arr2)
console.log(arr1)  //[1,2,3,4,5]

虽然直接用concat()也能将两个数组合并在一个数组,但它并不附加在现有数组上,而push.apply()可直接将被合并数组附加在现有数组上,同时若直接用push()会将被合并数组当做一个整体元素添加到现有数组里。

  1. 使用apply和内置函数
var numbers = [5, 6, 2, 3, 7];

//应用(apply) Math.min/Math.max 内置函数完成 
var max = Math.max.apply(null, numbers); 
//基本等同于 Math.max(numbers[0], ...) 或 Math.max(5, 6, ..)
var min = Math.min.apply(null, numbers);
  1. 指定this值和参数的函数结果
function f(x,y){
    console.log(x,y)
}
f.apply(null,[1,2]) // 1 2

bind

bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。

let obj={
    name:"Cris",
    age:2,
    f1:function(i){
        console.log(this.name+':'+this.age+i)
    }
}
let f2=obj.f1.bind({name:"jane",age:3},"岁")
f2(); // jane:3岁

f2指定了this{name:"jane",age:3},同时还指定了参数i为“岁”

apply、call、bind总结:

apply、call、bind 三者都是用来改变函数this对象的指向。

apply、call、bind 三者第一个参数都是this要指向的对象,也就是指定的上下文。

apply、call、bind 三者都可以利用后续参数传参。

bind是返回对应的函数,便于稍后调用。 apply、call 则是立即调用。