资讯专栏INFORMATION COLUMN

this总结【2】—— call/apply和bind

wudengzan / 1394人阅读

摘要:和概览我们要将归为一类,多带带归为一类三者的共同点是都可以指定和都是绑定在的原型上的,所以的实例都可以调用这三个方法至于为什么,看完这篇文章你就懂了如果你不懂什么是实例的话,请移步深入浅出面向对象和原型概念篇深入浅出面向对象和原型概念篇第一个

1.call/apply和bind概览

我们要将call/apply归为一类,bind多带带归为一类

三者的共同点是都可以指定this

call/apply和bind都是绑定在Function的原型上的,所以Function的实例都可以调用这三个方法

Function.prototype.call(this,arg1,arg2)
Function.prototype.apply(this,[arg1,arg2])
Function.prototype.bind(this,arg1,arg2)

至于为什么,看完这篇文章你就懂了:)

如果你不懂什么是实例的话,请移步深入浅出面向对象和原型【概念篇1】、深入浅出面向对象和原型【概念篇2】
2. call / apply —— 第一个参数是this(上下文) 2.1 作用和返回值
作用

调用函数

改变该函数this值

操作参数

返回值
返回值是你调用的方法的返回值,若该方法没有返回值,则返回undefined。
    window.a = 1

    function print(b, c) {
        console.log(this.a, b, c)
    }

    print(2, 3) // 1 2 3

    print.call({a: -1}, -2, -3) // -1 -2 -3
    print.apply({a: 0}, [-2, -3]) // 0 -2 -3

call()方法的作用和 apply() 方法是一样的,只有一个区别
call()方法接受的是若干个参数
apply()方法接受的是一个包含若干个参数的数组

2.2 apply传递数组的应用
    // 例子一
    // Math.max()不接收数组的传递,我们可以使用apply方法
    let answer = Math.max.apply(null, [2, 4, 3])
    console.log(answer) // 4

    // 注意下面三个等价
    Math.max.apply(null, [2, 4, 3])
    Math.max.call(null, 2, 4, 3)
    Math.max(2, 4, 3)
    // 例子二
    // 合并两个数组
    let arr1 = ["parsnip", "potato"]
    let arr2 = ["celery", "beetroot"]
    // 将第二个数组融合进第一个数组
    // 相当于 arr1.push("celery", "beetroot");
    Array.prototype.push.apply(arr1, arr2)
    // 注意!!!this的意思是谁调用了push这个方法
    // 所以当 this = arr1 后
    // 就成了 arr1 调用了 push方法
    // 所以上述表达式等价于 arr1.push("celery", "beetroot") 

    console.log(arr1)
    // ["parsnip", "potato", "celery", "beetroot"]

例子二中非常值得注意的就是arr2数组被拆开了,成了一个一个的参数

所以,apply经常性的作用之一就是将数组元素迭代为函数参数
    // 例子三
    Math.max.apply(null, [2, 4, 3]) // 完美运行
    arr1.push.apply(null, arr2) // 报错 Uncaught TypeError: Array.prototype.push called on null or undefined

    // 说明
    Math = {
        max: function (values) {
            // 没用到this值
        }
    }
    Array.prototype.push = function (items) {
        // this -> 调用push方法的数组本身
        // this为null的话,就是向null里push
        // Array.prototype.push called on null or undefined
    }
    // 下面三个值是完全等价的,因为this值已经是arr1
    Array.prototype.push.apply(arr1, arr2)
    arr1.push.apply(arr1, arr2)
    arr2.push.apply(arr1, arr2)
2.3 小测试
    function xx() {
        console.log(this)
    }
    xx.call("1") // ??
    xx() // ??
如果答案和你想的不一样,请移步this总结【1】—— this概览
3.bind
fun.bind(thisArg[, arg1[, arg2[, ...]]])
3.1作用

改变this

返回一个新函数

3.2 绑定函数、目标函数

实例使用bind()方法后会返回一个新的函数【绑定函数】
原函数为【目标函数】

我个人更喜欢用新函数原函数来区分,因为新名词越多,理解上的困难越大

那么新函数被调用时会发生什么呢?
下面一句话务必记住
其实就是把原函数call/apply一下,并指定你传递的this

    function xx() {
        console.log(this)
    }

    let foo = xx.bind({"name":"jason"})
    // foo —— 新函数【绑定函数】
    // xx —— 原函数【目标函数】

    foo()

    // 新函数调用时对原函数的操作
    
    // 下面是伪代码
    // function foo(){
    //     xx.call({"name":"jason"})
    // }

    // 1.给xx(原函数)指定this 2.调用xx(原函数)
    // 一定要注意这两步是在新函数被调用时才发生,不调用不发生
    // 你也可以总结为一句话,给原函数 call/apply 了一下
3.3 bind()传参和新函数【绑定函数】传参

bind(this,arg1)会将arg1插入到原函数【目标函数】的参数列表的开始位置

传递给新函数【绑定函数】的参数会跟在它们的后面

    function list() {
        // 原函数【目标函数】
        return Array.prototype.slice.call(arguments);
    }

    let listTest = list(1, 2, 3); // [1, 2, 3]

    // 新函数【绑定函数】
    let leadingThirtysevenList = list.bind(undefined, 37);

    let list1 = leadingThirtysevenList(); // [37]
    let list2 = leadingThirtysevenList(1, 2, 3); // [37, 1, 2, 3]
3.3 原生实现一个bind,使用 this + call/apply【重点】
思考过程
    // 实现bind其实就是实现bind的特点
    // 1.bind的第一个参数是this
    // 2.bind可以return一个新函数,这个新函数可以调用原函数并且可以指定其this,还可以接受参数
    // 3.bind返回的新函数传递的参数要在bind传递的参数的后面
代码
    Function.prototype._bind = function () {
        // 声明bind接受的参数【除去this】为bindArgs
        // 因为第一个参数是this,需要去掉
        let bindArgs = Array.prototype.slice.call(arguments, 1)
        let bindThis = arguments[1]
        // 声明原函数【目标函数】为targetObj
        let targetObj = this
        return function () {
            // return出来的的函数接受的参数为newArgs
            // 要在return出来的新函数里把bindArgs和newArgs合并,使用数组的concat方法
            let newArgs = Array.prototype.slice.call(arguments)
            return targetObj.apply(bindThis, bindArgs.concat(newArgs))
        }
    }
4. 既然都是指定this,为什么已经有call/apply,又要有bind呢? 4.1 你从未关注过函数的返回值
你在控制台输入console.log(1)为什么一个是1,一个是undefined?

1是执行console.log()方法的输出值,undefined是这个方法的返回值
所以,你要知道所有的函数都有返回值,一定要去关注一下函数的返回值
4.2 call/apply 与 bind 的返回值
xxx.call()/xxx.apply() 的返回值是由xxx本身的返回值决定的
xxx.bind() 的返回值是一个函数

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

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

相关文章

  • 根据一道题引发的callapplybind方法总结

    摘要:首先介绍一下和的定义和的作用是改变函数运行时的上下文环境改变的指向将绑定到或者说调用了里面的方法。方法返回的是修改过后的函数追梦子追梦子执行成功 这是一道今天遇到的面试题 showImg(https://segmentfault.com/img/bV8lco?w=330&h=222); 因为setTimeout属于匿名函数,this指向window,所以this.id = 1但还是先总...

    ormsf 评论0 收藏0
  • ES5 call,apply,bind方法总结(包括理解this的指向问题)

    总结call,apply,bind方法的理解使用和区别。 call,apply,bind这三个方法在JavaScript中是用来改变函数调用的this指向。那么改变函数this指向有什么用呢?我们先来看一段代码 var a= { name:harden, fn:function () { console.log(this.name); } } var b =...

    nanchen2251 评论0 收藏0
  • 前端基础知识总结

    摘要:关于前端中是个老生常谈的问题,总是说不清道不明,看这里。的大致用法,相信接触过前端的同学都知道,无非以下种。先想一下,两次执行后结果是什么。输出总结被谁调用指向谁,没有被调用的情况下,浏览器默认为。由于箭头函数中的,总是指向父级作用域。 关于this 前端中this是个老生常谈的问题,总是说不清道不明,看这里。this只能用在函数里面,相信全世界的人都知道。this就是函数在被执行的时...

    MageekChiu 评论0 收藏0
  • 前端基础:call,apply,bind的的理解

    摘要:和区别其实他们的作用是一样的,只是传递的参数不一样而已。接受个参数,第一个参数指定了函数体内对象的指向,第二个参数为数组或者一个类数组。看个栗子一个有意思的事在中,多次是无效的。而则会立即执行函数。 背景 前两天在做小程序的需求的时候用到bind的时候才想起自己对这三的东西的了解比较浅薄,这个时候用的时候就有点怕。时候还是要好好学习下,理解下怎么玩。 正文 先说call 和 apply...

    netmou 评论0 收藏0
  • javascript关于this 以及this的显示设置(applycallbind)

    摘要:如果连续呢结果会是什么结果还是第一个原因是,在中,多次是无效的。更深层次的原因,的实现,相当于使用函数在内部包了一个,第二次相当于再包住第一次故第二次以后的是无法生效的。 this 1.其实js中的this没那么难理解,当找不到this时记住一句话:谁调我,我就指谁!new 谁指谁 function text1(){ console.log(this); //指wind...

    LiveVideoStack 评论0 收藏0

发表评论

0条评论

wudengzan

|高级讲师

TA的文章

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