重學前端之 做爲前端,你應該喜歡call,bind,apply

一.前言

由於有了this,並且this的指向是玄學,指向不固定,誰調用他就指向誰,這個時候咱們就須要有人能夠站出來爲this指引咱們須要的方向,他們就是call,bind,apply
前端

可是學習call,bind,apply的時候,咱們須要瞭解this到底指向誰
傳送門:重學前端之 讓人心態爆炸的this究竟是個什麼玩意node

二.簡單修改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的指向,具體使用方法使用代碼來實現上述的相同的效果(此博文中不考慮嚴格模式)bash

call

學習call,bind,apply的使用時候,若是咱們想要更好的理解,咱們必須打破原先的認知,在之前咱們使用函數時,寫法是app

function add(x,y){
    return console.log(x+y)
}
add(1,2)    //3
複製代碼

這種寫法咱們能夠理解成是JS給咱們提供的語法糖,能夠減小代碼量使代碼簡潔,其實真正使用應該是dom

add.call(underfind,1,2) //3 
複製代碼

在MDN中對call的定義是函數

call() 方法使用一個指定的 this 值和單獨給出的一個或多個參數來調用一個函數。post

語法學習

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

咱們須要使用函數的時候,使用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)
}
複製代碼
相關文章
相關標籤/搜索