欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

深入了解JS之作用域和閉包

 更新時間:2020年06月16日 10:46:46   作者:Mikejiawei  
這篇文章主要介紹了JS之作用域和閉包的相關知識,文中講解非常詳細,代碼幫助大家更好的理解和學習,感興趣的朋友可以了解下

作用域和閉包

ECMAScript5: JS 的代碼沒有代碼塊;使用函數(shù)運行的機制進行創(chuàng)建閉包;閉包就是作用域的意思;

ES5中,JS中只有函數(shù)才可以創(chuàng)建能操作的作用域;

JavaScript中的內存也分為棧內存和堆內存。一般來說,棧內存中存放的是存儲對象的地址,而堆內存中存放的是存儲對象的具體內容。對于原始類型的值而言,其地址和具體內容都存在與棧內存中;而基于引用類型的值,其地址存在棧內存,其具體內容存在堆內存中。堆內存與棧內存是有區(qū)別的,棧內存運行效率比堆內存高,空間相對推內存來說較小,反之則是堆內存的特點。所以將構造簡單的原始類型值放在棧內存中,將構造復雜的引用類型值放在堆中而不影響棧的效率。

函數(shù)執(zhí)行時形成私有作用域

函數(shù)執(zhí)行的時候(直接目的:讓函數(shù)體中的代碼執(zhí)行)會形成一個新的私有的作用域(棧內存),供函數(shù)體中的代碼執(zhí)行;

  1. 給形參賦值
  2. 私有作用域下的預解釋
  3. 私有作用域下的代碼執(zhí)行

形成的新的私有的作用域還保護了里面的私有變量不受外界的影響,我們把函數(shù)的這種保護機制叫”閉包”:為什么要有作用域;因為變量要規(guī)定活動范圍的,為便于管理不同范圍的變量;所以要給變量設置活動范圍;

預解釋也是在各自的作用域里進行預解釋的;

function fn(){
 var a=1;
}
fn();
fn();
console.log(a);//Uncaught ReferenceError: a is not defined;

因為a沒有聲明和定義過,所以報錯了;

上面的fn運行了兩次,所以產(chǎn)生了兩個堆內存;兩個作用域(作用域也就是閉包)各自分別有一個a的變量;a的值都是數(shù)字1,但是兩個變量是不相等的;兩個a之間是沒有任何關系的;

就好比我們都屬于人類;我們都繼承了人類這個對象所具有的特征;我有一雙手,你也有一雙手,但是我們兩個人的手是沒有關系的;我的手不等于你的手;

全局變量和私有變量

  • 在全局作用域下聲明的變量是全局變量;
  • 在私有作用域中聲明的變量是私有變量;函數(shù)的形參也是私有的變量;

如何區(qū)分函數(shù)中出現(xiàn)的變量是私有的還是非私有的?

首先看是否為形參,然后看是否在私有作用域中聲明過(有沒有var過),兩者有其一就是私有的變量,那么在當前函數(shù)中不管什么位置出現(xiàn)都是私有的,和全局的沒有半毛錢的關系;如果兩者都沒有,說明不是私有的;如果一個函數(shù)中出現(xiàn)的變量不是私有的,那么會往其上級作用域查找,上級沒有則繼續(xù)查找,一直找到window為止,如果window也沒有呢?

如果是獲取:會報錯

function fn() {
 console.log(num);//Uncaught ReferenceError: num is not defined
}
fn();

如果是設置:不是私有的,找全局,全局沒有的話相當于給全局加一個

function fn() {
 num = 13;//相當于給window增加了一個叫做num的屬性名,屬性值是13 window.num=13;
}
fn();
console.log(num);//13

如何查找當前作用域的上級作用域?

當前作用域的上級作用域是誰和函數(shù)在哪執(zhí)行的沒有任何的關系,我們只需要看當前函數(shù)是在哪個作用域下定義的,那么它的上級作用域就是誰;

下面是查找上一級作用域,一直找到window的案例;

var total = 100;
function fn() {
 var total = 10;
 return function () {
  console.log(total);
 }//如果返回的是一個引用數(shù)據(jù)類型的值(對象、數(shù)組、函數(shù)...),首先是把這個值開辟一個內存空間,有一個地址,然后把內存地址返回 ->例如在這里其實返回的就是 return xxxfff111;
}
var f = fn();//f=xxxfff111;
f();
// 10

//輸出的結果是 10 還是 100 ? 為什么 ?

如果是在自執(zhí)行函數(shù)里呢?

var total = 100;
function fn() {
 var total = 10;
 return function () {
  console.log(total);
 }
}
var f = fn();//f=xxxfff111;
~function () {
  var total = 1200;
  f();//->;里面變量的上級作用域是誰
}();
// 10

下面代碼輸出的是什么?

var a=0;
var b="0";
function fn(){
 console.log(a);
  console.log(b);
  console.log(typeof a);
 console.log(typeof b);
  a="1";
  var b=1;
  console.log(a);
  console.log(b);
  console.log(typeof a);
  console.log(typeof b);
}
fn();//運行后會輸出什么?如果沒有這行代碼;函數(shù)fn的定義是沒有意義的;函數(shù)只聲明定義,而不運行是沒有任何意義的;
//0,undefined,"number","undefined","1",1,"string","number"

預解釋是作用域中的預解釋;js里是可以函數(shù)里面套函數(shù)的;都運行的時候,是在函數(shù)創(chuàng)建的作用域里再創(chuàng)建一個作用域;

下面是作用域的范圍;

var a="window";
console.log(a);//window
function father(){
  console.log(a);//undefined
  var a="father";
  console.log(a);//father
  function children(){
   console.log(b);//undefined
   console.log(a);//father
   var b="flag";
   a="children";
   console.log(a);//children
  }
  children();
  console.log(a);//children
}
father();
console.log(a);//window

JavaScript中的代碼執(zhí)行順序是從上到下逐條運行的;遇到function定義函數(shù)的代碼塊;直接跳過;遇到函數(shù)執(zhí)行的代碼;就找到引用的函數(shù)地址;開始跳到執(zhí)行函數(shù)產(chǎn)生的作用域中執(zhí)行代碼;等函數(shù)執(zhí)行完以后,再回到當前作用域執(zhí)行下面的代碼;

上面的代碼運行后,輸出的是

“window”,undefined,“father”,undefined,“father”,“children”,“children”,“window”

作用域鏈查找:當作用域套作用域的時候,children內找不到某個變量;會到children的父作用域father中找;當father中找不到的時候;會到father的父作用域找;一直找到window這個根作用域;屬于作用域鏈式查找;

函數(shù)運行產(chǎn)生的作用域

函數(shù)的運行是一個有生命周期的內存地址;

函數(shù)運行時,會創(chuàng)建一個內存地址(產(chǎn)生堆內存,函數(shù)保存的就是這個堆內存的地址),當此函數(shù)運行結束時,此內存地址又會銷毀;這個地址,我們無法保存;它的靈活的,活動的;有生命周期的;我們也沒有辦法給這個作用域起一個變量名字,也沒辦法保存這個作用域,JS不提供這種機制;

也就是說:在作用域外面是沒辦法控制作用域內部的數(shù)據(jù)的;只能在作用域內部控制;而且作用域內部的代碼可以控制外部的數(shù)據(jù);這種機制就叫做閉包,閉包與作用域鏈和函數(shù)的運行有關系的;

函數(shù)里的變量,就在這個內存里創(chuàng)建;我們可以把這個內存當成一個對象;那函數(shù)里的變量就是這個內存對象的屬性;

函數(shù)的定義和函數(shù)的執(zhí)行是兩碼事(fn和fn()的區(qū)別);函數(shù)的執(zhí)行與函數(shù)的定義地方無關;這個一定要理解!

閉包

作用域就是閉包;我理解的是相同的意思;只是不同人對這個機制的叫法不同;閉包是一種機制;并不是某種形式或者概念;最大的閉包就是window,我們可以把window當做一個閉包;

權威指南182頁中對閉包的解釋;

權威指南解釋:函數(shù)的執(zhí)行依賴于變量作用域,這個作用域是函數(shù)定義時決定的,而不是函數(shù)調用時決定的

注意:函數(shù)對象可以通過作用域鏈相互關聯(lián)起來;函數(shù)體內部的變量都可以保存在函數(shù)作用域內,這種特性叫閉包; 批注:這里和作用域鏈有關系的,和閉包沒有關系的;函數(shù)的作用域是誰,和在哪運行沒有關系;只和在哪兒定義有關系;

如下代碼;

var a=0;
function fn(){
 var a=1;
 function fm(){
  console.log(a);
 }
 return fm;
}
var testFn1=fn();//hanshu這個變量就相當于fm函數(shù);
testFn1();//相當于fm函數(shù)運行;此時輸出的是1;而不是0;雖然是在window中運行的;但是在fn中定義的;所以a找到的是fm上一級作用域fm的a;而不是window中的a;

作用域不銷毀的情況|內存釋放

作用域不銷毀的總結:當函數(shù)內return一個引用數(shù)據(jù)類型;并且函數(shù)外面有一個變量接收這個引用數(shù)據(jù)類型;此時的作用域是不銷毀的;

堆內存

對象數(shù)據(jù)類型或者函數(shù)數(shù)據(jù)類型在定義的時候首先都會開辟一個堆內存,堆內存有一個引用的地址,如果外面有變量等指到了這個地址,我們就說這個內存被占用了,就不能銷毀了;

堆內存釋放的問題->堆內存用來存儲引用數(shù)據(jù)類型值的

[谷歌]:瀏覽器會每隔一段時間,看我們的堆內存是否還有其他的東西引用著,如果還在被占用著,瀏覽器不會進行處理;但是如果我們的堆內存已經(jīng)沒有任何的東西占用了,那么瀏覽器會把這個堆內存進行回收釋放

[IE和火狐]:開辟了一個堆內存,我們有一個占用的時候瀏覽器記一個數(shù)(記錄有多少個占用這個內存),當我們減少引用的時候,瀏覽器會把記數(shù)減1,當記的數(shù)字減為0的時候,瀏覽器會把我們的堆內存回收釋放

var obj1 = {name: "張三"};
var obj2 = obj1;
//我們想要讓堆內存釋放/銷毀,只需要把所有引用它的變量值賦值為null即可,如果當前的堆內存沒有任何東西被占用了,那么瀏覽器會在空閑的時候把它銷毀...
obj1 = null;
obj2 = null;

以上就是深入了解JS之作用域和閉包的詳細內容,更多關于JavaScript 作用域和閉包的資料請關注腳本之家其它相關文章!

相關文章

  • js的hasownproperty使用示例

    js的hasownproperty使用示例

    我們在js中可能經(jīng)常會用到for in來遍歷對象中的屬性,當然for in中得到的屬性,只能是可枚舉的屬性,for in的時候,它會把對象的屬性(包括原型的屬性)遍歷一遍,看面看示例就明白了
    2014-03-03
  • js返回當前網(wǎng)頁的url

    js返回當前網(wǎng)頁的url

    利用下面的腳本方便返回當前網(wǎng)頁的url,一般自己可以根據(jù)需要利用
    2008-09-09
  • JavaScript入門之對象與JSON詳解

    JavaScript入門之對象與JSON詳解

    JSON是JavaScript中對象的字面量,是對象的表示方法,通過使用JSON,可以減少中間變量,使代碼的結構更加清晰,也更加直觀。使用JSON,可以動態(tài)的構建對象,而不必通過類來進行實例化,大大的提高了編碼的效率
    2011-10-10
  • 詳解JavaScript中循環(huán)控制語句的用法

    詳解JavaScript中循環(huán)控制語句的用法

    這篇文章主要介紹了詳解JavaScript中循環(huán)控制語句的用法,包括break語句和continue語句的使用方法,需要的朋友可以參考下
    2015-06-06
  • JavaScript中的Repaint和Reflow用法詳解

    JavaScript中的Repaint和Reflow用法詳解

    這篇文章主要介紹了JavaScript中的Repaint和Reflow用法詳解,是JS入門學習中的基礎知識,需要的朋友可以參考下
    2015-07-07
  • 如何做到打開一個頁面,過幾分鐘自動轉到另一頁面

    如何做到打開一個頁面,過幾分鐘自動轉到另一頁面

    如何做到打開一個頁面,過幾分鐘自動轉到另一頁面...
    2007-04-04
  • JavascriptES6新特性之map和reduce詳解

    JavascriptES6新特性之map和reduce詳解

    這篇文章主要為大家詳細介紹了ES6的新特性之map和reduce,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-02-02
  • js導航菜單(自寫)簡單大方

    js導航菜單(自寫)簡單大方

    一個簡單的多級下拉菜單菜單但是由于業(yè)務和樣式上的要求,為了簡潔找了好多都不適合于是自己寫了一個,曬出來與大家分享,感興趣的朋友可以參考下哈,希望可以幫助到你
    2013-03-03
  • 深入理解JavaScript系列(19):求值策略(Evaluation strategy)詳解

    深入理解JavaScript系列(19):求值策略(Evaluation strategy)詳解

    這篇文章主要介紹了深入理解JavaScript系列(19):求值策略(Evaluation strategy)詳解,本文講解了一般理論、按值傳遞、按引用傳遞、按共享傳遞(Call by sharing)、按共享傳遞是按值傳遞的特例等內容,需要的朋友可以參考下
    2015-03-03
  • JS暴虐查找法

    JS暴虐查找法

    JS暴虐查找法...
    2006-12-12

最新評論