javascript 執行環境,做用域鏈和閉包

首先看下這條語句:數組

(function($) {…})(jQuery);閉包

1.原理:函數

function(arg){…}
這就定義了一個匿名函數,參數爲argthis

而調用函數時,是在函數後面寫上括號和實參的,因爲操做符的優先級,函數自己也須要用括號,即:
(function(arg){…})(param)
這就至關於定義了一個參數爲arg的匿名函數,而且將param做爲參數來調用這個匿名函數spa

而(function($){…})(jQuery)則是同樣的,之因此只在形參使用$,是爲了避免與其餘庫衝突,因此實參用jQuery
至關於code

funtion output(s){…};對象

output(jQuery);blog

或者索引

var fn=function(s){…};fn(jQuery);內存

2.做用:

這種寫法的最大好處是造成閉包。在(function($) {…})(jQuery)在內部定義的函數和變量只能在此範圍內有效。

造成私有函數、私有變量的概念。

幾個概念:

一、執行環境(execution context):

每一個函數都有本身的執行環境,當執行流進入一個函數時,函數的環境就會被推入一個環境棧中。而在函數執行後,棧將其環境彈出,把控制權返回給以前的執行環境。

二、做用域鏈(scope chain):

函數的內部環境能夠經過做用域鏈訪問到全部的外部環境,可是外部環境卻不能夠訪問外部環境,這就是做用域

ES5中只有全局做用域和函數做用域,沒有塊級做用域。

(但在ES6中多了一個let,他能夠保證外層塊不受內層塊的影響。即內層塊造成了一個塊級做用域,這是let的一個特色。

它不簡單,由於在許多的函數嵌套的情景下,只有對它理解深入,才能更好的去分析。)

三、閉包 :指有權訪問另外一個函數做用域中的變量的函數

建立閉包的常見方式,就是在一個函數內部建立另外一個函數(一般是匿名函數)。

在一個函數a內部定義的另外一個函數b,當b在a以外被執行時,就會造成閉包。同時b函數仍然能夠訪問到a函數中的局部變量與函數。

弊端:閉包會攜帶包含他的函數的做用域,會比其餘函數佔用更多的內存。因此請慎用閉包

function fn(){
  var array=[];
  for(var i=0;i<10;i++){
     array[i]=function(){
        return i;
}
}
return array;
}
fn();//[ƒ, ƒ, ƒ, ƒ, ƒ, ƒ, ƒ, ƒ, ƒ, ƒ]

咱們的本意是獲得這個數組中每一個函數都能返回本身的索引值,但是獲得的是每一個函數卻都返回了10.

閉包保存的是定義它的那個函數內部的局部變量丶參數和其餘內部函數,也就是說保存的是這個函數執行上下文中的整個VO,而不是一個變量。上面代碼中的函數做用域鏈中都保存着fn的活動對象,他們引用的都是一個i,當fn返回時,i的值是10,因此每一個函數都引用保存i那個變量的同一個變量。咱們若是想獲得原先想獲得的那個結果,能夠加上另外一個匿名函數改變他的父做用域(其實應該是建立它的做用域),將它包裹起來。

function fn(){
  var array=[];
  for(var i=0;i<10;i++){
     array[i]=function(num){
        return function(){
           return num;
};
}(i);
}
return array;
}

這個匿名函數有一個參數num,同時是返回值。在調用每一個匿名函數時,傳入了變量i。因爲參數是按值傳遞的,因此i就會複製給num,而這個匿名函數的內部又建立了一個訪問num的閉包,返回後可以訪問到該匿名函數中的VO(包括參數),因而每一個函數返回的都是num的一個副本,因此能夠獲得不一樣的值。

其實,說了這麼多,咱們只要熟悉閉包的兩個應用場景,就能比較好的理解閉包的意義。

一.做爲函數的返回值.。做爲函數返回值被執行後仍然能夠訪問定義它的那個函數環境的VO。

function f(){
   var a=1;
   return function(){
      console.log(a);
}  
}

var g=f();
g();//1;

二.做爲一個函數的參數。做爲函數返回值被當作另外一個函數的參數傳入時,仍然是訪問定義它的那個函數環境的VO

function f(){
   var a=1;
   return function(){
      console.log(a);
}  
}
var g=f();
g();//1;


function F(fn){
var a=2;
fn();
}
F(g);//1

上面兩個小例子也正好說明了閉包能夠訪問定義它的那個函數做用域下的內部變量和內部函數。實際上是整個VO,因此還包含參數。

關於this對象

咱們知道,this對象是在運行時基於函數的執行環境綁定的,全局函數中,this=window;

當某個函數被做爲某個對象的方法調用時,this=對象

匿名函數的執行環境具備全局性,所以其this對象一般指向window

因此在閉包中使用this對象或arguments對象,必須將該對象的引用保存到閉包可以訪問到的另外一個變量中。

相關文章
相關標籤/搜索