中文字幕免费精品_亚洲视频自拍_亚洲综合国产激情另类一区_色综合咪咪久久

深入理解javascript作用域和閉包
來源:易賢網 閱讀:1208 次 日期:2014-10-15 15:30:04
溫馨提示:易賢網小編為您整理了“深入理解javascript作用域和閉包”,方便廣大網友查閱!

作用域

作用域是一個變量和函數的作用范圍,javascript中函數內聲明的所有變量在函數體內始終是可見的,在javascript中有全局作用域和局部作用域,但是沒有塊級作用域,局部變量的優先級高于全局變量,通過幾個示例來了解下javascript中作用域的那些“潛規則”(這些也是在前端面試中經常問到的問題)。

1. 變量聲明提前

示例1:

var scope="global";

function scopeTest(){

console.log(scope);

var scope="local"

}

scopeTest(); //undefined

此處的輸出是undefined,并沒有報錯,這是因為在前面我們提到的函數內的聲明在函數體內始終可見,上面的函數等效于:

var scope="global";

function scopeTest(){

var scope;

console.log(scope);

scope="local"

}

scopeTest(); //local

注意,如果忘記var,那么變量就被聲明為全局變量了。

2. 沒有塊級作用域

和其他我們常用的語言不同,在Javascript中沒有塊級作用域:

function scopeTest() {

var scope = {};

if (scope instanceof Object) {

var j = 1;

for (var i = 0; i < 10; i++) {

//console.log(i);

}

console.log(i); //輸出10

}

console.log(j);//輸出1

}

在javascript中變量的作用范圍是函數級的,即在函數中所有的變量在整個函數中都有定義,這也帶來了一些我們稍不注意就會碰到的“潛規則”:

>

var scope = "hello";

function scopeTest() {

console.log(scope);//①

var scope = "no";

console.log(scope);//②

}

在①處輸出的值竟然是undefined,簡直喪心病狂啊,我們已經定義了全局變量的值啊,這地方不應該為hello嗎?其實,上面的代碼等效于:

var scope = "hello";

function scopeTest() {

var scope;

console.log(scope);//①

scope = "no";

console.log(scope);//②

}

聲明提前、全局變量優先級低于局部變量,根據這兩條規則就不難理解為什么輸出undefined了。

作用域鏈

在javascript中,每個函數都有自己的執行上下文環境,當代碼在這個環境中執行時,會創建變量對象的作用域鏈,作用域鏈是一個對象列表或對象鏈,它保證了變量對象的有序訪問。

作用域鏈的前端是當前代碼執行環境的變量對象,常被稱之為“活躍對象”,變量的查找會從第一個鏈的對象開始,如果對象中包含變量屬性,那么就停止查找,如果沒有就會繼續向上級作用域鏈查找,直到找到全局對象中:

作用域鏈的逐級查找,也會影響到程序的性能,變量作用域鏈越長對性能影響越大,這也是我們盡量避免使用全局變量的一個主要原因。

閉包

基礎概念

作用域是理解閉包的一個前提,閉包是指在當前作用域內總是能訪問外部作用域中的變量。

function createClosure(){

var name = "jack";

return {

setStr:function(){

name = "rose";

},

getStr:function(){

return name + ":hello";

}

}

}

var builder = new createClosure();

builder.setStr();

console.log(builder.getStr()); //rose:hello

上面的示例在函數中返回了兩個閉包,這兩個閉包都維持著對外部作用域的引用,因此不管在哪調用總是能夠訪問外部函數中的變量。在一個函數內部定義的函數,會將外部函數的活躍對象添加到自己的作用域鏈中,因此上面實例中通過內部函數能夠訪問外部函數的屬性,這也是javascript模擬私有變量的一種方式。

注意:由于閉包會額外的附帶函數的作用域(內部匿名函數攜帶外部函數的作用域),因此,閉包會比其它函數多占用些內存空間,過度的使用可能會導致內存占用的增加。

閉包中的變量

在使用閉包時,由于作用域鏈機制的影響,閉包只能取得內部函數的最后一個值,這引起的一個副作用就是如果內部函數在一個循環中,那么變量的值始終為最后一個值。

//該實例不太合理,有一定延遲因素,此處主要為了說明閉包循環中存在的問題

function timeManage() {

for (var i = 0; i < 5; i++) {

setTimeout(function() {

console.log(i);

},1000)

};

}

上面的程序并沒有按照我們預期的輸入1-5的數字,而是5次全部輸出了5。再來看一個示例:

function createClosure(){

var result = [];

for (var i = 0; i < 5; i++) {

result[i] = function(){

return i;

}

}

return result;

}

調用createClosure()[0]()返回的是5,createClosure()[4]()返回值仍然是5。通過以上兩個例子可以看出閉包在帶有循環的內部函數使用時存在的問題:因為每個函數的作用域鏈中都保存著對外部函數(timeManage、createClosure)的活躍對象,因此,他們都引用著同一變量i,當外部函數返回時,此時的i值為5,所以內部的每個函數i的值也為5。

那么如何解決這個問題呢?我們可以通過匿名包裹器(匿名自執行函數表達式)來強制返回預期的結果:

9

function timeManage() {

for (var i = 0; i < 5; i++) {

(function(num) {

setTimeout(function() {

console.log(num);

}, 1000);

})(i);

}

}

或者在閉包匿名函數中再返回一個匿名函數賦值:

function timeManage() {

for (var i = 0; i < 10; i++) {

setTimeout((function(e) {

return function() {

console.log(e);

}

})(i), 1000)

}

}

//timeManager();輸出1,2,3,4,5

function createClosure() {

var result = [];

for (var i = 0; i < 5; i++) {

result[i] = function(num) {

return function() {

console.log(num);

}

}(i);

}

return result;

}

//createClosure()[1]()輸出1;createClosure()[2]()輸出2

無論是匿名包裹器還是通過嵌套匿名函數的方式,原理上都是由于函數是按值傳遞,因此會將變量i的值復制給實參num,在匿名函數的內部又創建了一個用于返回num的匿名函數,這樣每個函數都有了一個num的副本,互不影響了。

閉包中的this

在閉包中使用this時要特別注意,稍微不慎可能會引起問題。通常我們理解this對象是運行時基于函數綁定的,全局函數中this對象就是window對象,而當函數作為對象中的一個方法調用時,this等于這個對象(TODO 關于this做一次整理)。由于匿名函數的作用域是全局性的,因此閉包的this通常指向全局對象window:

9

var scope = "global";

var object = {

scope:"local",

getScope:function(){

return function(){

return this.scope;

}

}

}

調用object.getScope()()返回值為global而不是我們預期的local,前面我們說過閉包中內部匿名函數會攜帶外部函數的作用域,那為什么沒有取得外部函數的this呢?每個函數在被調用時,都會自動創建this和arguments,內部匿名函數在查找時,搜索到活躍對象中存在我們想要的變量,因此停止向外部函數中的查找,也就永遠不可能直接訪問外部函數中的變量了。總之,在閉包中函數作為某個對象的方法調用時,要特別注意,該方法內部匿名函數的this指向的是全局變量。

幸運的是我們可以很簡單的解決這個問題,只需要把外部函數作用域的this存放到一個閉包能訪問的變量里面即可:

var scope = "global";

var object = {

scope:"local",

getScope:function(){

var that = this;

return function(){

return that.scope;

}

}

}

object.getScope()()返回值為local。

內存與性能

由于閉包中包含與函數運行期上下文相同的作用域鏈引用,因此,會產生一定的負面作用,當函數中活躍對象和運行期上下文銷毀時,由于必要仍存在對活躍對象的引用,導致活躍對象無法銷毀,這意味著閉包比普通函數占用更多的內存空間,在IE瀏覽器下還可能會導致內存泄漏的問題,如下:

function bindEvent(){

var target = document.getElementById("elem");

target.onclick = function(){

console.log(target.name);

}

}

上面例子中匿名函數對外部對象target產生一個引用,只要是匿名函數存在,這個引用就不會消失,外部函數的target對象也不會被銷毀,這就產生了一個循環引用。解決方案是通過創建target.name副本減少對外部變量的循環引用以及手動重置對象:

function bindEvent(){

var target = document.getElementById("elem");

var name = target.name;

target.onclick = function(){

console.log(name);

}

target = null;

}

閉包中如果存在對外部變量的訪問,無疑增加了標識符的查找路徑,在一定的情況下,這也會造成性能方面的損失。解決此類問題的辦法我們前面也曾提到過:盡量將外部變量存入到局部變量中,減少作用域鏈的查找長度。

總結:閉包不是javascript獨有的特性,但是在javascript中有其獨特的表現形式,使用閉包我們可以在javascript中定義一些私有變量,甚至模仿出塊級作用域,但閉包在使用過程中,存在的問題我們也需要了解,這樣才能避免不必要問題的出現。

更多信息請查看IT技術專欄

更多信息請查看腳本欄目
易賢網手機網站地址:深入理解javascript作用域和閉包
由于各方面情況的不斷調整與變化,易賢網提供的所有考試信息和咨詢回復僅供參考,敬請考生以權威部門公布的正式信息和咨詢為準!

2026上岸·考公考編培訓報班

  • 報班類型
  • 姓名
  • 手機號
  • 驗證碼
關于我們 | 聯系我們 | 人才招聘 | 網站聲明 | 網站幫助 | 非正式的簡要咨詢 | 簡要咨詢須知 | 新媒體/短視頻平臺 | 手機站點 | 投訴建議
工業和信息化部備案號:滇ICP備2023014141號-1 云南省教育廳備案號:云教ICP備0901021 滇公網安備53010202001879號 人力資源服務許可證:(云)人服證字(2023)第0102001523號
云南網警備案專用圖標
聯系電話:0871-65099533/13759567129 獲取招聘考試信息及咨詢關注公眾號:hfpxwx
咨詢QQ:1093837350(9:00—18:00)版權所有:易賢網
云南網警報警專用圖標
中文字幕免费精品_亚洲视频自拍_亚洲综合国产激情另类一区_色综合咪咪久久
欧美jizzhd精品欧美巨大免费| 国产精品一区毛片| 好看不卡的中文字幕| 男女激情视频一区| 欧美岛国在线观看| 欧美日韩精品不卡| 欧美国产亚洲精品久久久8v| 久久亚洲私人国产精品va| 亚洲欧美日韩直播| 午夜精品久久久久久久久久久久久 | 欧美与黑人午夜性猛交久久久| 91久久在线观看| 一区二区在线看| 国产欧美综合在线| 国产啪精品视频| 国产日韩在线一区二区三区| 国产精品自在线| 国产精品久久久久久久久免费樱桃| 欧美日韩一区二区三区视频| 欧美高清在线播放| 欧美日韩亚洲91| 国产精品久久国产愉拍| 国产精品视频xxx| 国产亚洲一区二区三区在线播放| 国内精品一区二区三区| 国模套图日韩精品一区二区| 在线观看免费视频综合| 亚洲黄色成人| 日韩亚洲在线| 亚洲一区二区三区三| 亚洲欧美日韩天堂| 欧美中文字幕在线观看| 国产精品少妇自拍| 欧美一区=区| 久久精品二区亚洲w码| 久久久久国产精品一区| 美女精品国产| 欧美日韩成人综合在线一区二区| 国产精品jizz在线观看美国| 国产视频不卡| 亚洲黄色毛片| 亚洲一区视频在线观看视频| 久久久久久穴| 国产日韩欧美自拍| 韩国亚洲精品| 99精品国产高清一区二区 | 国产一区二区三区自拍| 尤物网精品视频| 艳妇臀荡乳欲伦亚洲一区| 午夜精品国产| 欧美精品免费观看二区| 国产日韩专区| 野花国产精品入口| 久久久久天天天天| 欧美无砖砖区免费| 亚洲天堂激情| 欧美亚洲视频| 欧美日韩高清免费| 韩日精品在线| 亚洲影院免费观看| 欧美精品97| 黄色亚洲精品| 午夜精品区一区二区三| 欧美理论电影网| 亚洲第一色在线| 久久er精品视频| 国产精品久久午夜| 9l国产精品久久久久麻豆| 蘑菇福利视频一区播放| 国产一区香蕉久久| 亚洲欧美综合网| 欧美体内谢she精2性欧美| 亚洲国产精品小视频| 欧美在线三区| 国产欧美日本一区视频| 亚洲一级片在线观看| 欧美第一黄色网| 永久域名在线精品| 久久久久久一区| 国产亚洲人成a一在线v站| 亚洲午夜视频| 国产精品久久久久久超碰| 最新日韩欧美| 久久精品国产99国产精品| 国产日本精品| 欧美亚洲一级片| 国产亚洲欧美日韩日本| 欧美亚洲三区| 国产精品五区| 欧美亚洲免费在线| 国产精品主播| 欧美一区二区三区喷汁尤物| 国产欧美91| 久久久精品一区| 在线看片第一页欧美| 噜噜噜躁狠狠躁狠狠精品视频| 精品99一区二区| 免费国产一区二区| 亚洲精品国精品久久99热| 欧美女同视频| 亚洲一区二区三| 国产日韩欧美在线观看| 久久在线免费观看视频| 亚洲人成绝费网站色www| 欧美日韩色综合| 午夜精品99久久免费| 国产亚洲欧美另类一区二区三区| 久久蜜桃精品| 亚洲乱码国产乱码精品精天堂| 欧美日韩三级| 亚洲欧美日韩国产一区二区三区| 国产视频一区在线观看一区免费| 久久精品伊人| 一本久久综合| 一区二区免费看| 午夜精品久久久久久久99樱桃| 久久婷婷蜜乳一本欲蜜臀| 欧美激情bt| 亚洲激情视频| 亚洲第一区在线| 999在线观看精品免费不卡网站| 亚洲国产成人一区| 欧美日韩成人在线播放| 国产日韩欧美精品一区| 在线精品国产成人综合| 最新日韩在线视频| 国产精品免费在线| 欧美刺激午夜性久久久久久久| 在线成人欧美| 久久九九国产精品怡红院| 欧美高清一区二区| 国产精品香蕉在线观看| 国产在线精品一区二区中文 | 快播亚洲色图| 麻豆freexxxx性91精品| 久久综合九色综合欧美就去吻| 欧美激情精品久久久六区热门 | 99pao成人国产永久免费视频| 久久久www成人免费精品| 欧美亚洲成人精品| 一区免费观看| 国产精品国产三级国产普通话蜜臀| 亚洲高清二区| 欧美激情按摩| 久久九九国产| 亚洲国产精品精华液2区45| 欧美一区不卡| 国产精品久久久久aaaa九色| 欧美亚洲专区| 日韩午夜在线视频| 久色成人在线| 欧美一激情一区二区三区| 狠狠干成人综合网| 亚洲激情视频| 牛牛影视久久网| 亚洲精品美女久久久久| 国产精品久久久一本精品| 欧美成人一区二区三区在线观看 | 欧美四级伦理在线| 一片黄亚洲嫩模| 欧美激情第9页| 野花国产精品入口| 欧美日本韩国一区二区三区| 日韩亚洲精品在线| 国产情人综合久久777777| 一本大道久久a久久精品综合| 国产伦精品一区二区三区四区免费 | 亚洲午夜极品| 欧美激情一区二区三区在线视频观看| 国产欧美一区二区三区久久人妖| 久久最新视频| 夜夜精品视频一区二区| 国产午夜一区二区三区| 一区二区三区www| 亚洲大黄网站| 极品尤物一区二区三区| 国产一区二区三区电影在线观看| 国产精品美腿一区在线看| 欧美精品一区二区三区视频| 欧美成人69av| 欧美xx视频| 欧美~级网站不卡| 欧美成人国产| 男女精品视频| 欧美大片91| 欧美国产日韩视频| 欧美日本中文字幕| 欧美日本视频在线| 欧美三级网址| 国产精品视频久久| 国产欧美日韩一区二区三区| 国产九九精品视频| 国产亚洲激情在线| 精品福利电影| 亚洲国产午夜| 在线视频日韩精品| 久久精品国产99国产精品| 欧美一区二区视频网站| 午夜精品久久久久久| 久久av免费一区|