接觸了不少nodejs的知識點,一直沒有作自我整理和概括,再次用到的時候仍是不清晰,這是病,得治。在此但願經過記錄的方式加深本身的理解。
總的來講:做用域與調用函數訪問變量的能力有關,上下文和this關鍵字有關,是當前可執行代碼的引用。javascript
做用域分爲局部做用域和全局做用域,做用域每每和變量存在關係。處在局部做用域裏面能夠訪問全局做用域的變量,而處在局部做用域外面不能訪問局部做用域裏面的變量。看代碼: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();
上下文經常表明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
使用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的方式。
本篇文章主要參考了慕課網,進擊nodejs基礎(一)中http源碼解讀部份內容,以及博客文章關於javascript中apply()和call()方法的區別,加上本身的理解整理所得,若有錯誤之處,歡迎指出。