JS-作用域及函數(shù)小結(jié)

一、作用域

了解作用域?qū)Τ绦驁?zhí)行的影響及作用域鏈的查找機制,使用閉包函數(shù)創(chuàng)建隔離作用域避免全局變量污染。

作用域(scope)規(guī)定了變量能夠被訪問的“范圍”贵涵,離開了這個“范圍”變量便不能被訪問,作用域分為全局作用域和局部作用域恰画。

1.1 局部作用域

局部作用域分為函數(shù)作用域和塊作用域宾茂。

函數(shù)作用域

在函數(shù)內(nèi)部聲明的變量只能在函數(shù)內(nèi)部被訪問,外部無法直接訪問拴还。

<script>
  // 聲明 counter 函數(shù)
  function counter(x, y) {
    // 函數(shù)內(nèi)部聲明的變量
    let s = x + y;
    console.log(s); // 18
  }

  // 設(shè)用 counter 函數(shù)
  counter(10, 8);

  // 訪問變量 s
  console.log(s); // 報錯
</script>

總結(jié):

  1. 函數(shù)內(nèi)部聲明的變量跨晴,在函數(shù)外部無法被訪問
  2. 函數(shù)的參數(shù)也是函數(shù)內(nèi)部的局部變量
  3. 不同函數(shù)內(nèi)部聲明的變量無法互相訪問
  4. 函數(shù)執(zhí)行完畢后,函數(shù)內(nèi)部的變量實際被清空了
塊作用域

在 JavaScript 中使用 {} 包裹的代碼稱為代碼塊自沧,代碼塊內(nèi)部聲明的變量外部將【有可能】無法被訪問坟奥。

<script>
  {
    // age 只能在該代碼塊中被訪問
    let age = 18;
    console.log(age); // 正常
  }
  
  // 超出了 age 的作用域
  console.log(age); // 報錯
  
  let flag = true;
  if(flag) {
    // str 只能在該代碼塊中被訪問
    let str = 'hello world!';
    console.log(str); // 正常
  }
  
  // 超出了 age 的作用域
  console.log(str); // 報錯
  
  for(let t = 1; t <= 6; t++) {
    // t 只能在該代碼塊中被訪問
    console.log(t); // 正常
  }
  
  // 超出了 t 的作用域
  console.log(t); // 報錯
</script>

JavaScript 中除了變量外還有常量,常量與變量本質(zhì)的區(qū)別是【常量必須要有值且不允許被重新賦值】拇厢,常量值為對象時其屬性和方法允許重新賦值爱谁。

<script>
  // 必須要有值
  const version = '1.0.0';

  // 不能重新賦值
  // version = '1.0.1';

  // 常量值為對象類型
  const user = {
    name: '小明',
    age: 18
  }

  // 不能重新賦值
  user = {};

  // 屬性和方法允許被修改
  user.name = '小小明';
  user.gender = '男';
</script>

總結(jié):

  1. let 聲明的變量會產(chǎn)生塊作用域,var 不會產(chǎn)生塊作用域
  2. const 聲明的常量也會產(chǎn)生塊作用域
  3. 不同代碼塊之間的變量無法互相訪問
  4. 推薦使用 letconst

注:開發(fā)中 letconst 經(jīng)常不加區(qū)分的使用孝偎,如果擔(dān)心某個值會不小被修改時访敌,則只能使用 const 聲明成常量。

1.2 全局作用域

<script> 標(biāo)簽和 .js 文件的【最外層】就是所謂的全局作用域衣盾,在此聲明的變量在函數(shù)內(nèi)部也可以被訪問寺旺。

<script>
  // 此處是全局
  
  function sayHi() {
    // 此處為局部
  }

  // 此處為全局
</script>

全局作用域中聲明的變量,任何其它作用域都可以被訪問势决,如下代碼所示:

<script>
    // 全局變量 name
    let name = '小明';
  
    // 函數(shù)作用域中訪問全局
    function sayHi() {
      // 此處為局部
      console.log('你好' + name);
    }

    // 全局變量 flag 和 x
    let flag = true;
    let x = 10;
  
    // 塊作用域中訪問全局
    if(flag) {
      let y = 5;
      console.log(x + y); // x 是全局的
    }
</script>

總結(jié):

  1. window 對象動態(tài)添加的屬性默認(rèn)也是全局的阻塑,不推薦!
  2. 函數(shù)中未使用任何關(guān)鍵字聲明的變量為全局變量果复,不推薦3旅А!!
  3. 盡可能少的聲明全局變量走搁,防止全局變量被污染

JavaScript 中的作用域是程序被執(zhí)行時的底層機制独柑,了解這一機制有助于規(guī)范代碼書寫習(xí)慣,避免因作用域?qū)е碌恼Z法錯誤私植。

1.3 作用域鏈

作用域鏈本質(zhì)上是底層的變量查找機制忌栅,在函數(shù)被執(zhí)行時,會優(yōu)先查找當(dāng)前函數(shù)作用域中查找變量曲稼,如果當(dāng)前作用域查找不到則會依次逐級查找父級作用域直到全局作用域索绪,如下代碼所示:

<script>
  // 全局作用域
  let a = 1;
  let b = 2;

  // 局部作用域
  function f() {
    let c;
    // let a = 10;
    console.log(a); // 1 或 10
    console.log(d); // 報錯
    
    // 局部作用域
    function g() {
      let d = 'yo';
      // let b = 20;
      console.log(b); // 2 或 20
    }
    
    // 調(diào)用 g 函數(shù)
    g()
  }

  console.log(c); // 報錯
  console.log(d); // 報錯
  
  f();
</script>

總結(jié):

  1. 嵌套關(guān)系的作用域串聯(lián)起來形成了作用域鏈
  2. 相同作用域鏈中按著從小到大的規(guī)則查找變量
  3. 子作用域能夠訪問父作用域,父級作用域無法訪問子級作用域(就近原則)

1.4 閉包

閉包是一種比較特殊和函數(shù)躯肌,使用閉包能夠訪問函數(shù)作用域中的變量者春。從代碼形式上看閉包是一個做為返回值的函數(shù),如下代碼所示:

<script>
  function foo() {
    let i = 0;

    // 函數(shù)內(nèi)部分函數(shù)
    function bar() {
            console.log(++i);
    }

    // 將函數(shù)做為返回值
    return bar;
  }
  
  // fn 即為閉包函數(shù)
  let fn = foo();
  
  fn(); // 1
</script>

總結(jié):

閉包:一個作用域有權(quán)訪問另外一個作用域的局部變量清女,

好處:可以把一個變量使用范圍延伸

  1. 閉包本質(zhì)仍是函數(shù),只不是從函數(shù)內(nèi)部返回的
  2. 閉包能夠創(chuàng)建外部可訪問的隔離作用域晰筛,避免全局變量污染
  3. 過度使用閉包可能造成內(nèi)存泄漏

注:回調(diào)函數(shù)也能訪問函數(shù)內(nèi)部的局部變量嫡丙。

1.5 變量提升

變量提升是 JavaScript 中比較“奇怪”的現(xiàn)象,它允許在變量聲明之前即被訪問读第,

<script>
  // 訪問變量 str
  console.log(str + 'world!');

  // 聲明變量 str
  var str = 'hello ';
</script>

let和var都有提升曙博,但是let定義的變量沒有賦值之前是不可以使用、var可以使用是undefined

總結(jié):

  1. 變量在未聲明即被訪問時會報語法錯誤
  2. 變量在聲明之前即被訪問怜瞒,變量的值為 undefined
  3. let 聲明的變量不存在變量提升父泳,推薦使用 let【也有人認(rèn)為具有提升但是不賦值不能使用】
  4. 變量提升出現(xiàn)在相同作用域當(dāng)中
  5. 實際開發(fā)中推薦先聲明再訪問變量

注:關(guān)于變量提升的原理分析會涉及較為復(fù)雜的詞法分析等知識,而開發(fā)中使用 let 可以輕松規(guī)避變量的提升吴汪。

二惠窄、函數(shù)

2.1 函數(shù)提升

函數(shù)提升與變量提升比較類似,是指函數(shù)在聲明之前即可被調(diào)用漾橙。

<script>
  // 調(diào)用函數(shù)
  foo();

  // 聲明函數(shù)
  function foo() {
    console.log('聲明之前即被調(diào)用...');
  }

  // 不存在提升現(xiàn)象
  bar();
  var bar = function () {
    console.log('函數(shù)表達式不存在提升現(xiàn)象...');
  }
</script>

總結(jié):

  1. 函數(shù)提升能夠使函數(shù)的聲明調(diào)用更靈活
  2. 函數(shù)表達式不存在提升的現(xiàn)象
  3. 函數(shù)提升出現(xiàn)在相同作用域當(dāng)中

2.2 參數(shù)

函數(shù)參數(shù)的使用細(xì)節(jié)杆融,能夠提升函數(shù)應(yīng)用的靈活度。

默認(rèn)值
<script>
  // 設(shè)置參數(shù)默認(rèn)值
  function sayHi(name="小明", age=18) {
    document.write(`<p>大家好霜运,我叫${name}脾歇,我今年${age}歲了。</p>`);
  }
  // 調(diào)用函數(shù)
  sayHi();
  sayHi('小紅');
  sayHi('小剛', 21);
</script>

總結(jié):

  1. 聲明函數(shù)時為形參賦值即為參數(shù)的默認(rèn)值
  2. 如果參數(shù)未自定義默認(rèn)值時淘捡,參數(shù)的默認(rèn)值為 undefined
  3. 調(diào)用函數(shù)時沒有傳入對應(yīng)實參時藕各,參數(shù)的默認(rèn)值被當(dāng)做實參傳入
動態(tài)參數(shù)

arguments 是函數(shù)內(nèi)部內(nèi)置的偽數(shù)組變量,它包含了調(diào)用函數(shù)時傳入的所有實參焦除。

<script>
  // 求生函數(shù)激况,計算所有參數(shù)的和
  function sum() {
    // console.log(arguments);
    let s = 0;
    for(let i = 0; i < arguments.length; i++) {
      s += arguments[i];
    }
    console.log(s);
  }

  // 調(diào)用求和函數(shù)
  sum(5, 10); // 兩個參數(shù)
  sum(1, 2, 4); // 兩個參數(shù)
</script>

總結(jié):

  1. arguments 是一個偽數(shù)組
  2. arguments 的作用是動態(tài)獲取函數(shù)的實參
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子誉碴,更是在濱河造成了極大的恐慌宦棺,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件黔帕,死亡現(xiàn)場離奇詭異代咸,居然都是意外死亡,警方通過查閱死者的電腦和手機成黄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門呐芥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人奋岁,你說我怎么就攤上這事思瘟。” “怎么了闻伶?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵滨攻,是天一觀的道長。 經(jīng)常有香客問我蓝翰,道長光绕,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任畜份,我火速辦了婚禮诞帐,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘爆雹。我一直安慰自己停蕉,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布钙态。 她就那樣靜靜地躺著慧起,像睡著了一般。 火紅的嫁衣襯著肌膚如雪驯绎。 梳的紋絲不亂的頭發(fā)上完慧,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天,我揣著相機與錄音剩失,去河邊找鬼屈尼。 笑死,一個胖子當(dāng)著我的面吹牛拴孤,可吹牛的內(nèi)容都是我干的脾歧。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼演熟,長吁一口氣:“原來是場噩夢啊……” “哼鞭执!你這毒婦竟也來了司顿?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤兄纺,失蹤者是張志新(化名)和其女友劉穎大溜,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體估脆,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡钦奋,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了疙赠。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片付材。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖圃阳,靈堂內(nèi)的尸體忽然破棺而出厌衔,到底是詐尸還是另有隱情,我是刑警寧澤捍岳,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布富寿,位于F島的核電站,受9級特大地震影響锣夹,放射性物質(zhì)發(fā)生泄漏作喘。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一晕城、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧窖贤,春花似錦砖顷、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至授嘀,卻和暖如春物咳,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蹄皱。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工览闰, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人巷折。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓压鉴,卻偏偏與公主長得像,于是被迫代替她去往敵國和親锻拘。 傳聞我的和親對象是個殘疾皇子油吭,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容