亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

深入理解Javascript作用域與變量提升

2019-11-20 21:30:21
字體:
供稿:網(wǎng)友

下面的程序是什么結(jié)果?

復(fù)制代碼 代碼如下:

var foo = 1;
function bar() {
 if (!foo) {
  var foo = 10;
 }
 alert(foo);
}
bar();

結(jié)果是10;

那么下面這個(gè)呢?

復(fù)制代碼 代碼如下:

var a = 1;
function b() {
 a = 10;
 return;
 function a() {}
}
b();
alert(a);

結(jié)果是1.

嚇你一跳吧?發(fā)生了什么事情?這可能是陌生的,危險(xiǎn)的,迷惑的,同樣事實(shí)上也是非常有用和印象深刻的javascript語言特性。對(duì)于這種表現(xiàn)行為,我不知道有沒有一個(gè)標(biāo)準(zhǔn)的稱呼,但是我喜歡這個(gè)術(shù)語:“Hoisting (變量提升)”。這篇文章將對(duì)這種機(jī)制做一個(gè)拋磚引玉式的講解,但是,首先讓我們對(duì)javascript的作用域有一些必要的理解。

Javascript的作用域

對(duì)于Javascript初學(xué)者來說,一個(gè)最迷惑的地方就是作用域;事實(shí)上,不光是初學(xué)者。我就見過一些有經(jīng)驗(yàn)的javascript程序員,但他們對(duì)scope理解不深。javascript作用域之所以迷惑,是因?yàn)樗绦蛘Z法本身長的像C家族的語言,像下面的C程序:

復(fù)制代碼 代碼如下:

#include <stdio.h>
int main() {
 int x = 1;
 printf("%d, ", x); // 1
 if (1) {
  int x = 2;
  printf("%d, ", x); // 2
 }
 printf("%d/n", x); // 1
}

輸出結(jié)果是1 2 1,這是因?yàn)镃家族的語言有塊作用域,當(dāng)程序控制走進(jìn)一個(gè)塊,比如if塊,只作用于該塊的變量可以被聲明,而不會(huì)影響塊外面的作用域。但是在Javascript里面,這樣不行??纯聪旅娴拇a:
復(fù)制代碼 代碼如下:

var x = 1;
console.log(x); // 1
if (true) {
 var x = 2;
 console.log(x); // 2
}
console.log(x); // 2

結(jié)果會(huì)是1 2 2。因?yàn)閖avascript是函數(shù)作用域。這是和c家族語言最大的不同。該程序里面的if并不會(huì)創(chuàng)建新的作用域。

對(duì)于很多C,c++,java程序員來說,這不是他們期望和歡迎的。幸運(yùn)的是,基于javascript函數(shù)的靈活性,這里有可變通的地方。如果你必須創(chuàng)建臨時(shí)的作用域,可以像下面這樣:

復(fù)制代碼 代碼如下:

function foo() {
 var x = 1;
 if (x) {
  (function () {
   var x = 2;
   // some other code
  }());
 }
 // x is still 1.
}

這種方法很靈活,可以用在任何你想創(chuàng)建臨時(shí)的作用域的地方。不光是塊內(nèi)。但是,我強(qiáng)烈推薦你花點(diǎn)時(shí)間理解javascript的作用域。它很有用,是我最喜歡的javascript特性之一。如果你理解了作用域,那么變量提升就對(duì)你顯得更有意義。

變量聲明,命名,和提升

在javascript,變量有4種基本方式進(jìn)入作用域:

•1 語言內(nèi)置:所有的作用域里都有this和arguments;(譯者注:經(jīng)過測(cè)試arguments在全局作用域是不可見的)

•2 形式參數(shù):函數(shù)的形式參數(shù)會(huì)作為函數(shù)體作用域的一部分;

•3 函數(shù)聲明:像這種形式:function foo(){};

•4 變量聲明:像這樣:var foo;

函數(shù)聲明和變量聲明總是會(huì)被解釋器悄悄地被“提升”到方法體的最頂部。這個(gè)意思是,像下面的代碼:

復(fù)制代碼 代碼如下:

function foo() {
 bar();
 var x = 1;
}

實(shí)際上會(huì)被解釋成:
復(fù)制代碼 代碼如下:

function foo() {
 var x;
 bar();
 x = 1;
}

無論定義該變量的塊是否能被執(zhí)行。下面的兩個(gè)函數(shù)實(shí)際上是一回事:
復(fù)制代碼 代碼如下:

function foo() {
 if (false) {
  var x = 1;
 }
 return;
 var y = 1;
}
function foo() {
 var x, y;
 if (false) {
  x = 1;
 }
 return;
 y = 1;
}

請(qǐng)注意,變量賦值并沒有被提升,只是聲明被提升了。但是,函數(shù)的聲明有點(diǎn)不一樣,函數(shù)體也會(huì)一同被提升。但是請(qǐng)注意,函數(shù)的聲明有兩種方式:
復(fù)制代碼 代碼如下:

function test() {
 foo(); // TypeError "foo is not a function"
 bar(); // "this will run!"
 var foo = function () { // 變量指向函數(shù)表達(dá)式
  alert("this won't run!");
 }
 function bar() { // 函數(shù)聲明 函數(shù)名為bar
  alert("this will run!");
 }
}
test();

這個(gè)例子里面,只有函數(shù)式的聲明才會(huì)連同函數(shù)體一起被提升。foo的聲明會(huì)被提升,但是它指向的函數(shù)體只會(huì)在執(zhí)行的時(shí)候才被賦值。

上面的東西涵蓋了提升的一些基本知識(shí),它們看起來也沒有那么迷惑。但是,在一些特殊場(chǎng)景,還是有一定的復(fù)雜度的。

變量解析順序

最需要牢記在心的是變量解析順序。記得我前面給出的命名進(jìn)入作用域的4種方式嗎?變量解析的順序就是我列出來的順序。

復(fù)制代碼 代碼如下:

<script>
function a(){ 
}
var a;
alert(a);//打印出a的函數(shù)體
</script>

<script>

var a;
function a(){ 
}
alert(a);//打印出a的函數(shù)體
</script>
//但是要注意區(qū)分和下面兩個(gè)寫法的區(qū)別:
<script>
var a=1;
function a(){ 
}
alert(a);//打印出1
</script>

<script>
function a(){ 
}

var a=1;

alert(a);//打印出1
</script>


這里有3個(gè)例外:

1 內(nèi)置的名稱arguments表現(xiàn)得很奇怪,他看起來應(yīng)該是聲明在函數(shù)形式參數(shù)之后,但是卻在函數(shù)聲明之前。這是說,如果形參里面有arguments,它會(huì)比內(nèi)置的那個(gè)有優(yōu)先級(jí)。這是很不好的特性,所以要杜絕在形參里面使用arguments;

2 在任何地方定義this變量都會(huì)出語法錯(cuò)誤,這是個(gè)好特性;

3 如果多個(gè)形式參數(shù)擁有相同的名稱,最后的那個(gè)具有優(yōu)先級(jí),即便實(shí)際運(yùn)行的時(shí)候它的值是undefined;

命名函數(shù)

你可以給一個(gè)函數(shù)一個(gè)名字。如果這樣的話,它就不是一個(gè)函數(shù)聲明,同時(shí),函數(shù)體定義里面的指定的函數(shù)名( 如果有的話,如下面的spam, 譯者注)將不會(huì)被提升, 而是被忽略。這里一些代碼幫助你理解:

復(fù)制代碼 代碼如下:

foo(); // TypeError "foo is not a function"
bar(); // valid
baz(); // TypeError "baz is not a function"
spam(); // ReferenceError "spam is not defined"

var foo = function () {}; // foo指向匿名函數(shù)
function bar() {}; // 函數(shù)聲明
var baz = function spam() {}; // 命名函數(shù),只有baz被提升,spam不會(huì)被提升。

foo(); // valid
bar(); // valid
baz(); // valid
spam(); // ReferenceError "spam is not defined"


怎么寫代碼

現(xiàn)在你理解了作用域和變量提升,那么這對(duì)于javascript編碼意味著什么?最重要的一點(diǎn)是,總是用var定義你的變量。而且我強(qiáng)烈推薦,對(duì)于一個(gè)名稱,在一個(gè)作用域里面永遠(yuǎn)只有一次var聲明。如果你這么做,你就不會(huì)遇到作用域和變量提升問題。

語言規(guī)范怎么說

我發(fā)現(xiàn)ECMAScript參考文檔總是很有用。下面是我找到的關(guān)于作用域和變量提升的部分:

如果變量在函數(shù)體類聲明,則它是函數(shù)作用域。否則,它是全局作用域(作為global的屬性)。變量將會(huì)在執(zhí)行進(jìn)入作用域的時(shí)候被創(chuàng)建。塊不會(huì)定義新的作用域,只有函數(shù)聲明和程序(譯者以為,就是全局性質(zhì)的代碼執(zhí)行)才會(huì)創(chuàng)造新的作用域。變量在創(chuàng)建的時(shí)候會(huì)被初始化為undefined。如果變量聲明語句里面帶有賦值操作,則賦值操作只有被執(zhí)行到的時(shí)候才會(huì)發(fā)生,而不是創(chuàng)建的時(shí)候。

我期待這篇文章會(huì)對(duì)那些對(duì)javascript比較迷惑的程序員帶來一絲光明。我自己也盡最大的可能去避免帶來更多的迷惑。如果我說錯(cuò)了什么,或者忽略了什么,請(qǐng)告知。

譯者補(bǔ)充

有位朋友提醒了我發(fā)現(xiàn)了IE下全局作用域下命名函數(shù)的提升問題:

我翻譯文章的時(shí)候是這么測(cè)試的:

復(fù)制代碼 代碼如下:

<script>
functiont(){
spam();
var baz = function spam() {alert('this is spam')};
}
t();
</script>

這種寫法, 即非全局作用域下的命名函數(shù)的提升,在ie和ff下表現(xiàn)是一致的. 我改成:
復(fù)制代碼 代碼如下:

<script>
spam();
var baz = function spam() {alert('this is spam')};
</script>

則ie下是可以執(zhí)行spam的,ff下不可以. 說明不同瀏覽器在處理這個(gè)細(xì)節(jié)上是有差別的.

這個(gè)問題還引導(dǎo)我思考了另2個(gè)問題,1:對(duì)于全局作用于范圍的變量,var與不var是有區(qū)別的. 沒有var的寫法,其變量不會(huì)被提升。比如下面兩個(gè)程序,第二個(gè)會(huì)報(bào)錯(cuò):

復(fù)制代碼 代碼如下:

<script>
alert(a);
var a=1;
</script>

復(fù)制代碼 代碼如下:

<script>
alert(a);
a=1;
</script>

2: eval中創(chuàng)建的局部變量是不會(huì)被提升的(它也沒辦法做到).
復(fù)制代碼 代碼如下:

<script>
var a = 1;
function t(){
 alert(a);
 eval('var a = 2');
 alert(a);
}
t();
alert(a);
</script>

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
欧美 日韩 国产一区二区在线视频| 神马电影网我不卡| 日韩国产高清视频在线| 黄色免费网站观看| 亚洲精品第一页| 欧美成人久久久免费播放| 国产精品特级毛片一区二区三区| 日韩一区二区三区高清| 日韩精品一区二区三区视频在线观看| 蜜臀久久99精品久久久久久宅男| 在线免费黄色毛片| 欧美丝袜一区二区三区| 亚洲综合成人在线| 精品网站999www| 精品女同一区二区三区在线播放| 免费在线观看的电影网站| 91浏览器在线视频| 亚洲你懂的在线视频| 亚洲精品视频啊美女在线直播| 欧美成人免费观看| 欧美成人精品福利在线视频| 国产精品专区在线| 日本免费在线视频不卡一不卡二| 久久影院电视剧免费观看| 国产日韩欧美视频| 一本一本久久a久久精品综合麻豆| 日本中文字幕精品—区二区| 一区二区三区中文字幕精品精品| 亚洲av成人精品一区二区三区在线播放| 成人免费高清视频| 91精品视频在线| www.91popny.com| 黄色片免费在线观看| 2020日本在线视频中文字幕| 91.com在线观看| 成人美女在线视频| 噜噜噜91成人网| 五月激情综合婷婷| 成**人特级毛片www免费| 久久久久黄久久免费漫画| www.com亚洲| 在线观看国产免费视频| av中文字幕一区二区三区| 超污网站在线观看| mm1313亚洲国产精品无码试看| 99精品视频在线| 91丨九色丨蝌蚪富婆spa| 新版中文字幕在线资源| 亚洲精品999| 日韩欧美国产一区二区三区| 999精品在线观看| 日韩av在线免播放器| 台湾无码一区二区| 国产手机av在线| 欧美国产禁国产网站cc| 天天色综合天天色| 久久久国产一区二区三区四区小说| 狠狠躁夜夜躁人人爽天天高潮| 茄子视频成人在线| 国产午夜久久av| 美女呻吟一区| 九九热精品视频在线播放| 首播影院在线观看免费观看电视| 久久成人精品一区二区三区| 日韩欧美中文字幕视频| 99视频国产精品免费观看| 欧美日韩在线免费观看| 外国成人毛片| 在线日本高清免费不卡| 中国特黄一级片| 亚洲一区二区三区精品在线| 啊啊啊好爽视频| 国产激情视频一区二区在线观看| 免费在线看黄色| 日本高清免费不卡视频| 久久免费区一区二区三波多野| 一区二区在线免费视频| 亚洲综合精品视频| 久热中文字幕在线精品免费| 中文字幕一区三区久久女搜查官| 免费观看成人鲁鲁鲁鲁鲁视频| 粉嫩aⅴ一区二区三区四区| 成人免费看片视频| 最近中文字幕mv免费高清视频8| 九色在线观看视频| 精品国产无码一区二区三区| 少妇高潮久久久久久潘金莲| 国产一区欧美二区三区| 午夜亚洲一区| 久久久精品国产99久久精品芒果| 污网站免费在线观看| 欧美精品三级在线观看| 日韩精品欧美成人高清一区二区| 成人高清伦理免费影院在线观看| 81精品国产乱码久久久久久| 国产黄色小视频在线观看| 欧美二区乱c少妇| 欧美三区视频| 婷婷五月精品中文字幕| 亚洲精品中文字幕乱码三区不卡| 日韩欧美一区二区在线| 巨骚激情综合| av大片在线免费观看| 无码aⅴ精品一区二区三区浪潮| 免费97视频在线精品国自产拍| 成人毛片在线精品国产| 天堂久久精品忘忧草| 亚洲国产一区二区三区青草影视| 囯产精品一品二区三区| 亚洲高清久久| 国产综合第一页| 九一精品在线观看| 成人免费黄色网| 97在线资源站| 每日在线观看av| 欧美哺乳videos| 日韩精品久久久久久久软件91| 国产xxx精品视频大全| 日日躁天天躁狠狠躁| 中文字幕一区二区三区蜜月| 日韩一区二区三区三四区视频在线观看| 国产成人精品白浆久久69| 一区二区三区四区五区在线| 成人日韩在线电影| 日韩久久精品成人| 午夜激情综合网| 欧美日韩加勒比精品一区| 国产精品一二三四五| 亚洲精品视频一区二区三区| 最近中文字幕mv2018在线高清| 五月天中文字幕| 亚洲欧美日韩综合| 日韩欧美第二区在线观看| 蜜臀久久精品久久久用户群体| 91精品国产91久久综合| 91在线视频免费播放| 亚洲一区欧美在线| 国产亚洲第一伦理第一区| 久久久久久在线观看| 欧美中文字幕在线| 欧美综合一区| 久久久久久高清| 韩国女主播一区二区| 免费黄色av网址| 伊人久久大香线蕉综合影院首页| 五月婷婷综合在线观看| 欧美一级日本a级v片| 高清免费电影在线观看| 我不卡手机影院| 精品免费在线观看| 91麻豆国产在线观看| 无码毛片aaa在线| 亚洲欧美日韩在线播放| 不卡视频一二三| 亚洲欧美日韩国产综合| 日本性高潮视频| 日韩av影院在线观看| 国产成人短视频在线观看| 成人午夜淫片100集| 亚洲精品成人| 色婷五月综激情亚洲综合| 国产老肥熟一区二区三区| 香蕉视频在线播放| 久久99精品网久久| 污污的网站免费| 久久综合九色综合97婷婷女人| 中国女人内谢25xxxxx| 先锋影音网一区| 天天综合天天色| ririsao久久精品一区| 成人在线看片网站| 欧美黑白配在线| 国产不卡一二三区| 午夜精品一区二区在线观看的| 欧美亚洲日本在线| 久久久久久国产精品美女| 久久噜噜色综合一区二区| 天堂а√在线8种子蜜桃视频| 粉嫩一区二区三区在线观看| 国产人妖乱国产精品人妖| 怡红院在线播放| 国产调教在线观看| 91精品免费久久久久久久久| 手机av免费在线| 91高清免费观看| 亚洲另类在线制服丝袜| 国产探花在线播放| 亚洲mv在线| 91短视频在线| 九九热只有这里有精品| 精品毛片三在线观看| 新片速递亚洲合集欧美合集| 日韩美女毛片| 日韩激情视频一区二区| 亚洲自拍另类欧美丝袜| 欧美乱人伦中文字幕在线| 欧美激情久久久久久| 欧美三级免费| 艳母动漫在线观看| 瑟瑟视频在线看| 99在线热播| 国产情侣呻吟对白高潮| 中文字幕+乱码+中文字幕明步| 91久久精品久久国产性色也91| 久久成人这里只有精品| 国产黄色一级电影| 国产亚洲在线播放| 一区二区欧美激情| 19j韩国主播韩宝贝在线| 美日韩丰满少妇在线观看| 午夜影院黄色片| 蜜桃精品一区二区| 国产成人精品无码免费看夜聊软件| 日韩免费不卡视频| 精品一区久久久| 精品欧美一区二区在线观看视频| 在线heyzo| 亚洲无人区一区| 懂色av成人一区二区三区| 日韩精品成人在线观看| 大香一本蕉伊线亚洲网| 国产精品日本欧美一区二区三区| 最近中文字幕大全中文字幕免费| 日韩污视频在线观看| 九九热视频免费在线观看| 国产伦理片在线观看| 国产精品亚洲综合一区在线观看| 91视频 - 88av| bdsm国产| 青草国产精品| 国产精品111| 久久久久久久毛片| 日韩**中文字幕毛片| 曰本人一级毛片免费完整视频| 国产网址在线观看| 国产欧美最新羞羞视频在线观看| 亚洲人成毛片在线播放| 日韩精品高清在线观看| 国内揄拍国内精品少妇国语| 国产九九在线观看| 欧美最猛性xxxxx喷水| 日本jizz中国| 欧美激情精品| 精品国产高清a毛片无毒不卡| 老头吃奶性行交视频| 欧美亚洲第一页| 亚洲v国产v在线观看| 亚州欧美精品suv| 日韩久久久久| 9久久婷婷国产综合精品性色| 成人免费视频网站在线观看| 免费看成人吃奶视频在线| 欧美毛片免费观看| 极品av少妇一区二区| 奇米777第四色| 久久影院午夜片一区| 日本在线观看一区| 99热精品久久| 亚洲香蕉中文网| dy888夜精品国产专区| 国产中文字幕二区| 羞羞视频在线观看不卡| 国产男女猛烈无遮挡免费视频| 99久久精品网站| 欧美黄色成人网| 亚洲欧美va天堂人熟伦| 波多野结衣高清在线| 亚洲视频一二区| 国产精品第八页| 欧美一区二区三区图| 国产女主播福利| 亚洲色图丝袜| 波多野结衣中文字幕在线播放| 国产精品成久久久久三级| 青青影院一区二区三区四区| 大肉大捧一进一出好爽| 九义人在线观看完整免费版电视剧| 色一情一欲一爱一乱| 97国产成人无码精品久久久| 国产视频二区三区| 久久精品性爱视频| 欧美自拍偷拍一区| 国产人成一区二区三区影院| 顶级嫩模一区二区三区| 欧美午夜免费影院| 黄网站app在线观看| 亚洲欧美日韩免费| 成人一级福利| 亚洲精品高清在线| 青青草国产免费自拍| 91欧美在线| 国产最新精品精品你懂的| 国产精品日韩在线播放| 国产精品毛片一区二区三区| 欧美电影免费观看| 色欧美激情视频在线| 精品日本美女福利在线观看| 国产麻豆成人传媒免费观看| 熟妇高潮一区二区高潮| 国产一区二区三区天码| 免费一区二区三区四区| 久久夜色精品国产| 亚洲精品国产九九九| 在线观看你懂得| 国产一区二区在线视频聊天| 国产对白videos麻豆高潮| 国产视频不卡| 91精品店在线| www.日日夜夜| 天天综合网久久| 国产一区二区播放| 美女与牲口做爰视频在线观看| 嫩模一区二区三区| 在线 亚洲欧美在线综合一区| 欧美极品在线观看| 91网址在线观看| 99国产精品一区二区| 任你弄在线视频免费观看| 免费无码av片在线观看| 久草中文在线视频| 欧美一区综合| 99久久国产综合精品女小说| 亚洲成av人影院| 影音先锋制服丝袜| 91精品国产综合久久福利软件| 久久97精品久久久久久久不卡| 日本午夜精品久久久| 男人天堂久久久|