一篇文章告訴你JavaScript的作用域和函數(shù)該這樣理解
一、作用域
【解釋】: 規(guī)定了變量能夠被訪問的“范圍”,離開了這個“范圍”變量便不能被訪問。
【分類】:
局部作用域全局作用域
1.1 局部作用域
【分類】:
數(shù)作用域塊作用域
1、函數(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 } // 調(diào)用 counter 函數(shù) counter(10, 8); // 訪問變量 s console.log(s); // 報錯 外部無法訪問函數(shù)內(nèi)部的變量 </script>
【總結(jié)】:
- 函數(shù)內(nèi)部聲明的變量,在函數(shù)外部無法被訪問
- 函數(shù)的參數(shù)也是函數(shù)內(nèi)部的局部變量
- 不同函數(shù)內(nèi)部聲明的變量無法互相訪問
- 函數(shù)執(zhí)行完畢后,函數(shù)內(nèi)部的變量實際被清空了
2、塊作用域
【解釋】: 在 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'; // 不能重新賦值 // version = '1.1'; // 常量值為對象類型 const user = { name: '小明', age: 18 } // 不能重新賦值 user = {}; // 屬性和方法允許被修改 user.name = '小小明'; user.gender = '男'; </script>
【總結(jié)之let、var、const】:
let 聲明的變量會產(chǎn)生塊作用域,var 不會產(chǎn)生塊作用域
const聲明的常量也會產(chǎn)生塊作用域
不同代碼塊之間的變量無法互相訪問
推薦使用 let
或 const
開發(fā)中 let
和 const
經(jīng)常不加區(qū)分的使用,如果擔(dān)心某個值會不小被修改時,則只能使用 const
聲明成常量。
關(guān)鍵字 | 塊級作用域 | 變量提升 | 初始值 | 更改值 | 通過window調(diào)用 |
---|---|---|---|---|---|
let | √ | × √ | - | √ | × |
const | √ | × √ | √ | × | × |
var | × | √ | - | √ | √ |
1.2 全局作用域
【解釋】: <script>
標(biāo)簽和 js 文件的【最外層】就是所謂的全局作用域,在此聲明的變量在函數(shù)內(nèi)部也可以被訪問。
【示例】:
<script> // 此處是全局 function sayHi() { // 此處為局部 } // 此處為全局 </script> <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é)】:
- 為
window
對象動態(tài)添加的屬性默認(rèn)也是全局的,不推薦! - 函數(shù)中未使用任何關(guān)鍵字聲明的變量為全局變量,不推薦?。。?/li>
- 盡可能少的聲明全局變量,防止全局變量被污染
1.3 作用域鏈
【解釋】: 函數(shù)內(nèi)部允許創(chuàng)建新的函數(shù),f
函數(shù)內(nèi)部創(chuàng)建的新函數(shù) g
,會產(chǎn)生新的函數(shù)作用域,由此可知作用域產(chǎn)生了嵌套的關(guān)系。作用域鏈本質(zhì)上是底層的變量查找機制,在函數(shù)被執(zhí)行時,會優(yōu)先查找當(dāng)前函數(shù)作用域中查找變量,如果當(dāng)前作用域查找不到則會依次逐級查找父級作用域直到全局作用域
【示例】:
<script> // 全局作用域 let a = 1; let b = 2; // 局部作用域 function f() { let c; // 局部作用域 function g() { let d = 'yo'; } } </script>
<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é)】:
- 嵌套關(guān)系的作用域串聯(lián)起來形成了作用域鏈
- 相同作用域鏈中按著從小到大的規(guī)則查找變量
- 子作用域能夠訪問父作用域,父級作用域無法訪問子級作用域(就近原則)
1.4、閉包
【解釋】: 閉包是一種比較特殊和函數(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é)】:
- 閉包本質(zhì)仍是函數(shù),只不是從函數(shù)內(nèi)部返回的
- 閉包能夠創(chuàng)建外部可訪問的隔離作用域,避免全局變量污染
- 過度使用閉包可能造成內(nèi)存泄漏‘
- 回調(diào)函數(shù)也能訪問函數(shù)內(nèi)部的局部變量。
1.5 變量提升
【解釋】: 允許在變量聲明之前即被訪問
【示例】:
<script> // 訪問變量 str console.log(str + 'world!'); // 聲明變量 str var str = 'hello '; </script> let和var都有提升,但是let定義的變量沒有賦值之前是不可以使用、var可以使用是undefined
【總結(jié)】:
- 變量在未聲明即被訪問時會報語法錯誤
- 變量在聲明之前即被訪問,變量的值為 `undefinedlet
聲明的變量不存在變量提升,推薦使用
let`【也有人認(rèn)為具有提升但是不賦值不能使用】- 變量提升出現(xiàn)在相同作用域當(dāng)中
- 實際開發(fā)中推薦先聲明再訪問變量
二、函數(shù)
2.1、函數(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ù)表達(dá)式不存在提升現(xiàn)象...'); } </script>
【總結(jié)】:
- 函數(shù)提升能夠使函數(shù)的聲明調(diào)用更靈活
- 函數(shù)表達(dá)式不存在提升的現(xiàn)象
- 函數(shù)提升出現(xiàn)在相同作用域當(dāng)中
2.2、函數(shù)參數(shù)
1、默認(rèn)參數(shù)
【示例】:
<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é)】:
- 聲明函數(shù)時為形參賦值即為參數(shù)的默認(rèn)值
- 如果參數(shù)未自定義默認(rèn)值時,參數(shù)的默認(rèn)值為
undefined
- 調(diào)用函數(shù)時沒有傳入對應(yīng)實參時,參數(shù)的默認(rèn)值被當(dāng)做實參傳入
2、動態(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>
【注意】:
- arguments是一個偽數(shù)組
- arguments的作用是動態(tài)獲取函數(shù)的實參
3、剩余參數(shù)
【語法及示例】:
<script> function config(baseURL, ...other) { console.log(baseURL); // other 是真數(shù)組,動態(tài)獲取實參 console.log(other); } // 調(diào)用函數(shù) config('http://baidu.com', 'get', 'json'); </script>
2.3、箭頭函數(shù)
【解釋】: 箭頭函數(shù)是一種聲明函數(shù)的簡潔語法,它與普通函數(shù)并無本質(zhì)的區(qū)別,差異性更多體現(xiàn)在語法格式上。
【示例】:
<script> // 箭頭函數(shù) let foo = () => { console.log('^_^ 長相奇怪的函數(shù)...'); } // 調(diào)用函數(shù) foo(); // 更簡潔的語法 let form = document.querySelector('form'); form.addEventListener('click', ev => ev.preventDefault()); </script>
【總結(jié)】:
- 箭頭函數(shù)屬于表達(dá)式函數(shù),因此不存在函數(shù)提升
- 箭頭函數(shù)只有一個參數(shù)時可以省略圓括號 `()
- 箭頭函數(shù)函數(shù)體只有一行代碼時可以省略花括號
{}
,并自動做為返回值被返回 - 箭頭函數(shù)中沒有
arguments
,只能使用...
動態(tài)獲取實參 - 涉及到this的使用,不建議用箭頭函數(shù)
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
前端編碼規(guī)范(3)JavaScript 開發(fā)規(guī)范
這篇文章主要介紹了前端編碼規(guī)范(3)JavaScript 開發(fā)規(guī)范,需要的朋友可以參考下2017-01-01使用Java實現(xiàn)簡單的server/client回顯功能的方法介紹
本篇文章介紹了,使用Java實現(xiàn)簡單的server/client回顯功能的方法。需要的朋友參考下2013-05-05簡介JavaScript中Boolean.toSource()方法的使用
這篇文章主要介紹了簡介JavaScript中Boolean.toSource()方法的使用,是JS入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下2015-06-06JavaScript中日期的相關(guān)操作方法總結(jié)
這篇文章主要介紹了JavaScript中日期的相關(guān)操作方法總結(jié),是JS入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下2015-10-10Javascript基礎(chǔ)_簡單比較undefined和null 值
下面小編就為大家?guī)硪黄狫avascript基礎(chǔ)_簡單比較undefined和null 值。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-06-06解析js如何獲取當(dāng)前url中的參數(shù)值并復(fù)制給input
本篇文章是對js獲取當(dāng)前url中的參數(shù)值并復(fù)制給input的方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06