资讯专栏INFORMATION COLUMN

细说apply call和bind

JasinYip / 2468人阅读

摘要:会创建一个新的函数,成为绑定函数,目标函数和绑定函数有共同的函数体。新的目标函数被调用的时候,就会绑定到函数的第一个参数上,且该参数不能被重写。当新的目标函数被创建的时候,目标函数的的值通过被设成了传入的参数的值。

bind 概述

bind方法是绑定在了Function.prototype上。这个方法会创建一个新的函数,当被调用时,会将其this关键字,设置为一个提供的值。

bind()会创建一个新的函数,成为绑定函数,目标函数和绑定函数有共同的函数体。新的目标函数被调用的时候,this就会绑定到bind()函数的第一个参数上,且该参数不能被重写。在函数调用的时候,也可以为目标函数增加新的参数,参数跟在第一个参数之后。

bind绑定this指向
var a = "hello 222"
var obj = {
    "a":"hello 111",
    say:function(){
        return this.a
    }
}


var otherSay = obj.say


console.log(obj.say())       //hello 111
console.log(otherSay())      //hello 222

我们都知道,this的指向取决于函数的调用而不是生命的位置,所以,otherSay()被调用的this指向全局对象,这时候a并不是obj里边定义的。所以会输出"hello 222"。

我们可以使用bind来改变otherSay()的this指向。当然call和apply也能做到。但是bind和另外两个方法是不一样的。

var newSay = otherSay.bind(obj)
console.log(newSay())

绑定函数newSay(),目标函数otherSay().用bind执行完操作后,两个函数共用同样一个执行环境,不管怎么调用,两个函数都有同样的this值。

背后的实现

bind是绑定在了Function的原型上。它是ES5提出来的,用了ES3的apply作为背后的实现。

Function.prototype.bind = function(obj){
    var _self = this
    return function(){
        return    _self.apply(obj)
    }
}

当新的目标函数被创建的时候,目标函数的this的值通过apply被设成了传入的参数的值。因为,我们传入我们想要的函数上下文,当函数调用的时候this就会指向了第一个参数。

函数柯里化
函数柯里化的概念是只传给函数一部分参数就能调用他,让他返回一个新的函数去处理另外的参数。
function add(x){
    return function(y){
        return x+y
    }
}

var add1 = add(10)
add1(20)          //30
add1(-10)         // 0

用bind()可以实现函数的柯里化

function gender,age,name){
    var salutation = gender === “male” ? “Mr” : "Ms"
    if(age > 25){
        return "hello" + salutation + name
    } else{
        return "hey" + name
    }
}

这是一个很简单的函数,很好理解。

接下来,我们使用柯里化greet()方法.bind()接收的第一个参数指定的this的值。

var greetMaleAdult = greet.bind(null,"name",44)
greetMaleAdult("Peter")

var greetChild = greet(null,"",12)
greetChild("Bob")

使用bind函数,可以将greet函数柯里化,我们只需要指定最后一个参数来执行柯里化之后的新函数,因为前边两个参数,d都在greet里边定义好了。

apply和call 概述

这两个方法放在一起将,因为两个函数基本上没有区别。
两个函数都是写到了Function.prototype上面。本质上这两个方法可以帮助我们实现函数借用和指定函数的this值。apply()允许我们传入一个参数数组来传给函数,供这个函数使用。

改变this

当我们使用这两个函数的时候,传入的第一个参数作为this的目标指向。

var age = 11
function showAge(){
    console.log(this.age)
}

var Man = {
    age:15
}
showAge.apply(Man)      // 立即返回15

我们看到,加了一行代码,我们改变了showAge中的this指向,开始的时候,全局函数showAge中的指向是全局对象,但是,我们通过apply函数,把this指向了一个对象Man,这个时候,会立即返回函数的执行结果15

apply和bind不一样的地方在于,bind不会立即返回结果,会返回一个新的函数,我们调用这个函数,才会返回结果
var age = 11
function showAge(){
    console.log(this.age)
}

var Man = {
    age:15
}

showAge.bind(Man)    // 并不会立即执行
showAge.bind(Man)()   // 执行返回的函数,显示15

另外,在回调函数中,我们也可以通过apply或者call方法手动设置this的指向。

var obj = {
    fullname:"not set",
    showName:function(firstname,lastname){
        this.fullname = firstname + " " +lastname
    }
}

function getFullname(firstname,lastname,callback,callbackobj){
    callback.call(callbackobj,firstname,lastname)   
}

getFullname("zhang","heihei",obj.showName,obj)
console.log(obj.fullname)   // zhang heihei  
函数借用

call和apply的存在可以让我们借用其他对象的函数来处理。最典型的例子就是我们可以通过函数借用来让类数组对象使用数据的方法。

var arrayLikeObj = {
    "0":"haha",
    "1":1,
    "2":true,
    "3":[1,2,3],
    length:4
}

var newArr = Array.prototype.slice.call(arrayLikeObj,0)  // ["haha",1,true,Array[3]]

var index = Array.prototype.indexOf.apply(arrayLikeObj,1)   //1

这样操作的好处就是既可以保留对象上的那些属性,又可以随时使用数组的方法。

总结

三个函数的最大区别在于:bind函数是返回一个函数(内部实现也是用的apply)供后续调用,而call和apply是立即调用返回执行结果。

另外,在箭头函数中,apply和call会失效,因为,箭头函数的this是确定的,是所在的执行上下文,而不是调用的时候的函数使用者。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/93142.html

相关文章

  • 「干货」细说 callapply 以及 bind 的区别用法

    摘要:的调用者,将会指向这个对象。此外,还可以扩展自己的其他方法。的使用最后来说说。不同的是,方法的返回值是函数,并且需要稍后调用,才会执行。而和则是立即调用。总结和的主要作用,是改变对象的执行上下文,并且是立即执行的。 前言 上一篇文章 《「前端面试题系列4」this 的原理以及用法》 中,提到了 call 和 apply。 它们最主要的作用,是改变 this 的指向。在平时的工作中,除了...

    GraphQuery 评论0 收藏0
  • 手写callapplybind及相关面试题解析

    摘要:我是前端我的全名是我是一个前端指向接收多个参数,第一个是返回值返回值是一个函数上下文的,不会立即执行。柯里化相关讲解请移步简版的实现就算完成了欢迎吐槽点赞 它们有什么不同?怎么用? call 接收多个参数,第一个为函数上下文也就是this,后边参数为函数本身的参数。 let obj = { name: 一个 } ...

    TwIStOy 评论0 收藏0
  • this全面解析(二)

    摘要:在传统的面向类的语言中,构造函数是类中的一些特殊方法,使用初始化类是会调用类中的构造函数。 在上一节中我们详细介绍了this的两种绑定方式,默认绑定和隐式绑定,在这一节我们继续介绍this的另外两种绑定方式显示绑定和new绑定。那么,我们要解决的问题当然就是上一节中我们提到的:this丢失! 显式绑定 在隐式绑定中,我们必须在一个对象的内部包含一个指向函数的属性,并通过这个属性间接引用...

    iflove 评论0 收藏0
  • 浅谈细说 JS 函数(call,apply,重载)

    摘要:什么是函数引用的原话函数是一组可以随时随地运行的语句。函数是由这样的方式进行声明的关键字函数名一组参数,以及置于括号中的待执行代码。 什么是函数? 引用 W3School 的原话: 函数是一组可以随时随地运行的语句。 函数是 ECMAScript 的核心。 函数是由这样的方式进行声明的:关键字 function、函数名、一组参数,以及置于括号中的待执行代码。 函数的基本语法是这样的:...

    U2FsdGVkX1x 评论0 收藏0
  • 细说 Javascript 函数篇(二) : this 的工作机制

    摘要:与其他编程语言相比,对的使用是一套完全不同的机制。在五种情况下的值是各有不同的。调用一个函数时在这里,同样指向全局对象。此时在函数内,指向新建的对象。尽管,晚绑定初看上去是个不好的决定,但实际上这是原型式继承工作的基础。 与其他编程语言相比,Javascript 对 this 的使用是一套完全不同的机制。this 在五种情况下的值是各有不同的。 全局作用域下 this; 当在全...

    ZoomQuiet 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<