重学前端之 作为前端,你应该喜欢call,bind,apply

一.前言

因为有了this,而且this的指向是玄学,指向不固定,谁调用他就指向谁,这个时候我们就需要有人可以站出来为this指引我们需要的方向,他们就是call,bind,apply

但是学习call,bind,apply的时候,我们需要了解this到底指向谁
传送门:重学前端之 让人心态爆炸的this到底是个什么玩意

二.简单修改this指向

    <input type="text">
    <script>
        var spa = {
            init:function(node){
                this.int = node.querySelector('input')
                this.str = '你对节点进行操作了'
                this.bind()
            },
            bind:function(){
                var _this = this
                this.int.onkeyup = function(){
                    console.log(_this.str)
                }
            }
        }
        let node = document.querySelector('body')
       spa.init(node)
    </script>
复制代码

上述代码中,应为DOM节点的操作,所以执行的函数内部this指向变成了这个被操作的dom节点,这个时候我们想添加前缀打印str这个值是单纯的使用this是获取不到的,我们在这个节点操作外部使用了一个小手法暂存了this的作用域,复制给_this,这个时候在函数内部就可以获取到与外面相同的作用域来获取str这个属性值了,那么既然改变this的指向,我们为什么还需要学习call,bind,apply呢,其实我觉得吧,这种写法没有逼格,既然js提供了相对应的API,我们就应该去学习使用,这样可以减少代码量使代码美观,也可以增强js内功,在第四节会奉上使用call,apply以及bind修改this指向代码,首先我们来了解一下他们吧

三.初探call,bind,apply

他们三个作用都是一样的,都是用于改变this的指向,具体使用方法使用代码来实现上述的相同的效果(此博文中不考虑严格模式)

call

学习call,bind,apply的使用时候,如果我们想要更好的理解,我们必须打破原先的认知,在以前我们使用函数时,写法是

function add(x,y){
    return console.log(x+y)
}
add(1,2)    //3
复制代码

这种写法我们可以理解成是JS给我们提供的语法糖,可以减少代码量使代码简洁,其实真正使用应该是

add.call(underfind,1,2) //3 
复制代码

在MDN中对call的定义是

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

语法

fun.call(thisArg, arg1, arg2, ...)

我们需要使用函数的时候,使用call这个方法可以传入两个或两个以上参数,第一个参数我们执行上下文,也就是我们的this,如果传入的是underfind,那么他就会指向全局对象,后续参数即函数需要的参数,那如果我们使用曾经默认的函数调用方法,他默认为func.call(underfind,...),这样就会函数的this指向全局,所以说为什么一般情况下函数是全局对象window的方法

再看call

看到了基本使用方法,我们试一试如何去使用他,有什么好玩的地方

    var a = 'hello'
    function printStr(){
        var a = 'world'
        return a
    }
    printStr()  //'world'
复制代码

这个时候我们想让他打印'world',而是想让他打印'hello'呢

   var a = 'hello'
    function printStr(){
        var a = 'world'
        return console.log(this.a)
    }
    printStr.call(undefined)    //hello
复制代码

我们通过this来专门指向特定的变量a,然后通过call改变this的指向以此来达到打印输出的是全局变量a,再来一个例子来看一下

    var a = 1,
        b = 2,
        c = 3,
        obj = {
            a:'hello ',
            b:'world ',
            c:'!'
        }
        function add(){
            return console.log(this.a+this.b+this.c)
        }
    add()       //6 等同于add.call(underfind)
    add.call(obj)   //'hello world !' 修改了this指向,让this指向了obj 
复制代码
apply

apply的使用方法和call基本相同,只不过在穿入执行上下文的时候,后面的参数是个数组而已

MDN定义

apply() 方法调用一个具有给定this值的函数,以及作为一个数组(或类似数组对象)提供的参数。

语法

func.apply(thisArg, [argsArray])

bind

bind也是穿入参数改变执行上下文,但是他会返回一个已经被改变this的函数

<input type="text">
    <script>
        var value = 'str'
        var node =  document.querySelector('input')
        node.onkeyup = strValue.bind(this)  //str

        function strValue(){
            console.log(this.value)
        }
    </script>
复制代码

keyup事件触发的时候,我们会发现我们打印的是str,因为我们在bind函数内穿入了执行上下文this,这个时候this的指向就是全局,所以打印的value就是str

如果我们想让他打印input框内容,只需要把代码修改为

node.onkeyup = strValue.bind(node)
复制代码

四.call,apply,bind修改作用域

call
 var spa = {
            init:function(node){
                this.int = node.querySelector('input')
                this.str = '你对节点进行操作了'
                this.bind()
            },
            bind:function(){
                this.int.onkeyup = ()=>{
                    this.printStr.call(spa)
                }
            },
            printStr:function(){
                console.log(this.str)
            }
        }
        let node = document.querySelector('body')
       spa.init(node)
}
复制代码
apply
var spa = {
            init:function(node){
                this.int = node.querySelector('input')
                this.str = '你对节点进行操作了'
                this.bind()
            },
            bind:function(){
                this.int.onkeyup = ()=>{
                    this.printStr.apply(spa)
                }
            },
            printStr:function(){
                console.log(this.str)
            }
        }
        let node = document.querySelector('body')
       spa.init(node)
复制代码

apply的用法是几乎是一样的,但是具体差别在哪,一会我们再说

bind
        var spa = {
            init:function(node){
                this.int = node.querySelector('input')
                this.str = '你对节点进行操作了'
                this.bind()
            },
            bind:function(){
                this.int.onkeyup = this.printStr.bind(this)
            },
            printStr:function(){
               console.log(this.str)
            }
        }
        let node = document.querySelector('body')
        spa.init(node)
}
复制代码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值