国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

學習JavaScript閉包和作用域筆記

Meils / 2526人閱讀

摘要:當函數被調用的時候,作用域鏈就會包含多個作用域對象。但是當函數要訪問時,并沒有找到,于是沿著作用域鏈向上查找,在的作用域找到了對應的標示符,就會修改的值。

JS JavaScript閉包和作用域 閉包
JavaScript高級程序設計中對閉包的定義:閉包是指有權訪問另外一個函數作用域中變量的函數。

從概念上,閉包有兩個特點:

函數

能訪問另外一個函數的作用域中的變量

ES6之前,JavaScript只有函數作用域的概念,沒有塊級作用域(但catch捕獲的異常,只能在catch中訪問)的概念。每個函數都是封閉的,外部訪問不到函數作用域中的變量。

function getName() {
  var name = "LHH";
  console.log(name);     //"LHH"
}
function displayName() {
    console.log(name);  //報錯
}

把代碼改成以下:

function getName() {
  var name = "LHH";
  function displayName() {
    console.log(name);   
  }
  return displayName;
}
var getLHH = getName();  
getLHH()  //"LHH"
函數是一個閉包,外部就可以訪問函數中的變量

對于閉包有下面三個特性:

1.閉包可以訪問當前函數以外的變量
function getOuter(){
  var date = "815";
  function getDate(str){
    console.log(str + date);  //訪問外部的date
  }
  return getDate("今天是:"); //"今天是:815"
}
getOuter();
getData是一個閉包,該函數執行時,會形成一個作用域AA中并沒有定義變量data,但它能從父一級作用域中找到該變量的定義。
2.即使外部函數已經返回,閉包仍能訪問外部函數定義的變量
function getOuter(){
  var date = "815";
  function getDate(str){
    console.log(str + date);  //訪問外部的date
  }
  return getDate;     //外部函數返回
}
var today = getOuter();
today("今天是:");   //"今天是:815"
today("明天不是:");   //"明天不是:815"
3.閉包可以更新外部變量的值
function updateCount(){
  var count = 0;
  function getCount(val){
    count = val;
    console.log(count);
  }
  return getCount;     //外部函數返回
}
var count = updateCount();
count(815); //815
count(816); //816
作用域鏈

JavaScript中有一個執行環境(execution context)的概念,它定義了變量或函數有權訪問的其他數據,決定了他們各自的行為。每個執行環境都有一個與之關聯的變量對象,環境中定義的所有變量和函數都保存在這個對象中。可以修改它的屬性,但不能引用它。

變量對象也是有父作用域的。當訪問一個變量時,解釋器會首先在當前作用域查找標識符,如果沒有找到,就去父作用域找,直到找到該變量的標識符或者不再存在父作用域鏈了,這就是作用域鏈。

作用域鏈和原型繼承有點類似:如果去查找一個普通對象的屬性時,在當前對象和其原型中都找不到時,會返回undefined,但查找的屬性在作用域中不存在的話就會拋出ReferenceError

作用域頂端是全局對象。對于全局環境中的代碼,作用域中只包含一個元素:全局對象。所以,在全局環境中定義變量的時候,它們會被定義到全局對象中。當函數被調用的時候,作用域鏈就會包含多個作用域對象。

1.全局環境

看一個例子:

// my_script.js
"use strict";
var foo = 1;
var bar = 2;

在全局環境中,創建了兩個簡單地變量。此時變量對象是全局對象:

執行上述代碼,my_script.js本身會形成一個執行環境,以及它所引用的變量對象。

2.無嵌套函數(Non-nested functions)
"use strict";
var foo = 1;
var bar = 2;
function myFunc() {
  //-- define local-to-function variables
  var a = 1;
  var b = 2;
  var foo = 3;
  console.log("inside myFunc");
}
console.log("outside");
//-- and then, call it:
myFunc();

myFunc被定義的時候,myFunc的標識符(identifier)就被加到了當前的作用域對象中(在這里就是全局對象),并且這個標識符所引用的是一個函數對象(function object)。函數對象中所包含的是函數的源代碼以及其他的屬性。內部屬性[[scope]]指向的就是當前的作用域對象。也就是指的就是函數的標識符被創建的時候,我們所能夠直接訪問的那個作用域對象(在這里就是全局對象)。

myFune所引用的函數對象,其本身不僅僅含有函數的代碼,并且還含有指向其創建的時候的作用域對象。

myFunc函數被調用的時候,一個新的作用域對象的被創建了。新的作用域對象中包含了myFunc函數所定義的的本地變量,以及其參數(arguments)。這個新的作用域對象的父作用域對象就是在運行myFunc時我們所能直接訪問的那個作用域對象(即全局對象)。

所以,當myFunc被執行的時候,對象之間的關系如下圖:

3.有嵌套的函數(Nested functions)

當函數返回沒有被引用的時候,就會被垃圾回收器回收。但是對于閉包(函數嵌套是形成閉包的一種形式),即使外部函數返回了,函數對象仍會引用它被創建時的作用域對象。

"use strict";
function createCounter(initial) {
  var counter = initial;
  function increment(value) {
    counter += value;
  }
  function get() {
    return counter;
  }
  return {
    increment: increment,
    get: get
  };
}
var myCounter = createCounter(100);
console.log(myCounter.get());   // 返回 100
myCounter.increment(5);
console.log(myCounter.get());   // 返回 105

當調用createCounter(100)時,對象之間的關系如下圖所示:

內嵌函數incrementget都有指向createCounter(100) scope的應用。如果createCounter(100)沒有任何返回值,那么createCounter(100) scope不再被引用,于是就可以被垃圾回收。但是因為createCounter(100)實際上是有返回值的,并且返回值被存儲在了myCounter中,所以對象之間的引用關系變成了如下圖所示:

即使createCounter(100)已經返回,但是其作用域仍在,并能且只能被內聯函數訪問。可以通過調用myCounter.increment()myCounter.get()來直接訪問createCounter(100)的作用域。

myCounter.increment() myCounter.get()被調用時,新的作用域對象會被創建,并且該作用域對象的父作用域對象會是當前可以直接訪問的作用域對象。此時,引用關系如下:

當執行到return counter;時,在get()所在的作用域并沒有找到對應的標示符,就會沿著作用域鏈往上找,直到找到變量counter,然后返回該變量。

當多帶帶調用increment(5)時,參數value會存貯在當前的作用域對象。函數要訪問value,能馬上在當前作用域找到該變量。但是當函數要訪問counter時,并沒有找到,于是沿著作用域鏈向上查找,在createCounter(100)的作用域找到了對應的標示符,increment()就會修改counter的值。除此之外,沒有其他方式來修改這個變量。閉包的強大也在于此,能夠存貯私有數據。

相同的函數,不同的作用域

//myScript.js
"use strict";
function createCounter(initial) {
  /* ... see the code from previous example ... */
}
//-- create counter objects
var myCounter1 = createCounter(100);
var myCounter2 = createCounter(200);

myCounter1 myCounter2創建之后,關系圖如下:

在上面的例子中,myCounter1.incrementmyCounter2.increment的函數對象擁有著一樣的代碼以及一樣的屬性值(namelength等等),但是它們的[[scope]]指向的是不一樣的作用域對象。

這才有了下面的結果:

var a, b;
a = myCounter1.get();   // a 等于 100
b = myCounter2.get();   // b 等于 200
myCounter1.increment(1);
myCounter1.increment(2);
myCounter2.increment(5);
a = myCounter1.get();   // a 等于 103
b = myCounter2.get();   // b 等于 205

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/108870.html

相關文章

  • 學習筆記JavaScript 閉包是怎么通過作用鏈霸占更多內存的?

    摘要:閉包是怎么通過作用域鏈霸占更多內存的本文是作者學習高級程序設計第一小節的一點個人理解,詳細教程請參考原教材。函數執行過程創建了一個函數的活動對象,作用域鏈的最前端指向這個對象。函數執行完畢返回值后執行環境作用域鏈和活動對象一并銷毀。 JavaScript 閉包是怎么通過作用域鏈霸占更多內存的? 本文是作者學習《JavaScript 高級程序設計》7.2第一小節的一點個人理解,詳細教程請...

    HmyBmny 評論0 收藏0
  • [學習筆記] JavaScript 閉包

    摘要:但是,必須強調,閉包是一個運行期概念。通過原型鏈可以實現繼承,而與閉包相關的就是作用域鏈。常理來說,一個函數執行完畢,其執行環境的作用域鏈會被銷毀。所以此時,的作用域鏈雖然銷毀了,但是其活動對象仍在內存中。 學習Javascript閉包(Closure)javascript的閉包JavaScript 閉包深入理解(closure)理解 Javascript 的閉包JavaScript ...

    sunsmell 評論0 收藏0
  • Js學習筆記閉包

    摘要:一前言這個周末,注意力都在學習基礎知識上面,剛好看到了閉包這個神圣的東西,所以打算把這兩天學到的總結下來,算是鞏固自己所學。因此要注意閉包的使用,否則會導致性能問題。五總結閉包的作用能夠讀取其他函數內部變量。 # 一、前言 這個周末,注意力都在學習基礎Js知識上面,剛好看到了閉包這個神圣的東西,所以打算把這兩天學到的總結下來,算是鞏固自己所學。也可能有些不正確的地方,也請大家看到了,麻...

    Crazy_Coder 評論0 收藏0
  • JS學習筆記(第7章)(函數表達式)

    摘要:遞歸閉包模仿塊級作用域私有變量小結在編程中,使用函數表達式可以無需對函數命名,從而實現動態編程。匿名函數也稱為拉姆達函數。函數聲明要求有名字,但函數表達式不需要。中的函數表達式和閉包都是極其有用的特性,利用它們可以實現很多功能。 1、遞歸 2、閉包 3、模仿塊級作用域 4、私有變量 5、小結 在JavaScript編程中,使用函數表達式可以無需對函數命名,從而實現動態編程。匿名函數也稱...

    xiaokai 評論0 收藏0
  • 重學前端學習筆記(十八)--JavaScript閉包執行上下文

    摘要:申明與賦值立即執行的函數表達式,通過創建一個函數,并且立即執行,來構造一個新的域,從而控制的范圍。函數接受一個的形參,該參數是一個對象引用,并執行了。在最新的標準中,引入了一個新概念。 筆記說明 重學前端是程劭非(winter)【前手機淘寶前端負責人】在極客時間開的一個專欄,每天10分鐘,重構你的前端知識體系,筆者主要整理學習過程的一些要點筆記以及感悟,完整的可以加入winter的專欄...

    silencezwm 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<