nodejs中call和apply的學習

接觸了不少nodejs的知識點,一直沒有作自我整理和概括,再次用到的時候仍是不清晰,這是病,得治。在此但願經過記錄的方式加深本身的理解。

1.引子:做用域與上下文


總的來講:做用域與調用函數訪問變量的能力有關,上下文和this關鍵字有關,是當前可執行代碼的引用。javascript

1.1做用域

做用域分爲局部做用域和全局做用域,做用域每每和變量存在關係。處在局部做用域裏面能夠訪問全局做用域的變量,而處在局部做用域外面不能訪問局部做用域裏面的變量。看代碼:html

var globalVariable = 'this is global variable';

function globalFunction(){
    var localVariable = 'this is local variable';
    console.log(globalVariable);   //this is global variable
    console.log(localVariable);   //this is local variable

    globalVariable = 'globalVariable has changed';

    function innerFunction(){
        var innerLocalVariable = 'this is inner local variable';
  
        console.log(globalVariable);   //globalVariable has changed
        console.log(localVariable);   //this is local variable
        console.log(innerLocalVariable);   //this is inner local variable
    }
    innerFunction();
}

globalFunction();
1.2上下文

上下文經常表明this變量的值以及它的指向,它決定一個函數怎麼被調用,當一個函數被做爲一個對象的方法調用時,this老是指向調用方法的對象。java

var pet = {
    words: '...',
    speak: function(){
        console.log(this.words);     //'...'
        console.log(this === pet);   // true
    }
}
pet.speak();

'==='表示不只值相等,類型也相同,this指向調用speak方法的pet對象,對比下面代碼:node

function pet(words){
    this.words = words;
    console.log(words);   //'...'
    console.log(this === pet)   //false
    console.log(this === global)   //true
}
pet('...');

此處的this指向運行環境的頂層的global對象,這裏能夠直接使用console.log(this)查看。繼續看一段代碼:數組

function Pet(words){
    this.words = words;
    this.speak = function(){
        console.log(this.words);   //miao
        console.log(this);    //打印出當前對象{words:'miao',speak:[Function]}
    }
}

var cat = new Pet('miao');
cat.speak();

*注:引入箭頭函數=>後,this不是指向函數調用的對象, 而是其父級對象app

var words= 'global';
var pet = {
    words: '...',
    speak: () => {
        console.log(this.words);     //'global'
        console.log(this === pet);   // false
    }
}
pet.speak();  // pet的父級對象Window

2.call和apply

使用call和apply能夠改變上下文執行對象,能夠在自定義上下文中執行函數,二者做用相同,僅僅是方法的第二個參數不一樣,call直接使用參數列表,apply使用參數數組。具體做用是調用一個對象的方法,以另外一個對象替換當前對象,實際上市改變this指向的對象內容。看代碼:ide

var pet = {
    words: '...',
    speak: function(say){
        console.log(say + ' ' + this.words);
    }
}
pet.speak('Speck');   // Speck ...

沒毛病!,修改代碼,再看一下:函數

var pet = {
    words: '...',
    speak: function(say){
        console.log(say + ' ' + this.words);
    }
}

var dog = {
    words:'wang'
}

pet.speak.call(dog,'Speak');   // Speak wang

dog對象原本沒有speak方法,經過call的方法,偷樑換柱地將本來指向pet的this變量指向了dog,所以在運行時,this.words='wang',因此打印出Speak wang。經過這種方式,咱們可使一個對象去使用另外一個對象的方法,一個容易想到的應用場景就是繼承。this

function Pet(words){
    this.words = words;
    this.speak = function(){
        console.log(this.words);
    }
}

function Dog(words){
    //Pet.call(this,words);  // Pet中的this指向當前的Dog,使Dog擁有Pet的方法
    Pet.apply(this,[words]);  // apply中的第二個參數是一個數組
}

var dog = new Dog('wang');
dog.speak();

咱們能夠看到,使用call和apply實現的效果是同樣的,僅僅是參數的差別,一個直接使用words,一個要使用數組形式的[words]。再看一個例子:code

function print(a, b, c, d){
    alert(a + b + c + d);
}
function example(a, b , c , d){
    //用call方式借用print,參數顯式打散傳遞
    print.call(this, a, b, c, d);

    //用apply方式借用print, 參數做爲一個數組傳遞,

    //能夠直接用JavaScript方法內自己有的arguments數組
    print.apply(this, arguments);

    //或者封裝成數組
    print.apply(this, [a, b, c, d]);
}

至於何時使用call,何時使用apply,通常當參數比較明確的時候,二者均可以,當參數不明確時,推薦使用apply+arguments的方式。

3.結束語

本篇文章主要參考了慕課網,進擊nodejs基礎(一)中http源碼解讀部份內容,以及博客文章關於javascript中apply()和call()方法的區別,加上本身的理解整理所得,若有錯誤之處,歡迎指出。

相關文章
相關標籤/搜索