一篇文章告訴你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ū)分的使用,如果擔心某個值會不小被修改時,則只能使用 const 聲明成常量。
| 關(guān)鍵字 | 塊級作用域 | 變量提升 | 初始值 | 更改值 | 通過window調(diào)用 |
|---|---|---|---|---|---|
| let | √ | × √ | - | √ | × |
| const | √ | × √ | √ | × | × |
| var | × | √ | - | √ | √ |
1.2 全局作用域
【解釋】: <script> 標簽和 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)添加的屬性默認也是全局的,不推薦! - 函數(shù)中未使用任何關(guān)鍵字聲明的變量為全局變量,不推薦!??!
- 盡可能少的聲明全局變量,防止全局變量被污染
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)先查找當前函數(shù)作用域中查找變量,如果當前作用域查找不到則會依次逐級查找父級作用域直到全局作用域
【示例】:
<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`【也有人認為具有提升但是不賦值不能使用】- 變量提升出現(xiàn)在相同作用域當中
- 實際開發(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ù)表達式不存在提升現(xiàn)象...');
}
</script>
【總結(jié)】:
- 函數(shù)提升能夠使函數(shù)的聲明調(diào)用更靈活
- 函數(shù)表達式不存在提升的現(xiàn)象
- 函數(shù)提升出現(xiàn)在相同作用域當中
2.2、函數(shù)參數(shù)
1、默認參數(shù)
【示例】:
<script>
// 設(shè)置參數(shù)默認值
function sayHi(name="小明", age=18) {
document.write(`<p>我叫${name},我今年${age}歲了。</p>`);
}
// 調(diào)用函數(shù)
sayHi();
sayHi('小紅');
sayHi('小剛', 21);
</script>
【總結(jié)】:
- 聲明函數(shù)時為形參賦值即為參數(shù)的默認值
- 如果參數(shù)未自定義默認值時,參數(shù)的默認值為
undefined - 調(diào)用函數(shù)時沒有傳入對應實參時,參數(shù)的默認值被當做實參傳入
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ù)屬于表達式函數(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入門學習中的基礎(chǔ)知識,需要的朋友可以參考下2015-06-06
JavaScript中日期的相關(guān)操作方法總結(jié)
這篇文章主要介紹了JavaScript中日期的相關(guān)操作方法總結(jié),是JS入門學習中的基礎(chǔ)知識,需要的朋友可以參考下2015-10-10
Javascript基礎(chǔ)_簡單比較undefined和null 值
下面小編就為大家?guī)硪黄狫avascript基礎(chǔ)_簡單比較undefined和null 值。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-06-06
解析js如何獲取當前url中的參數(shù)值并復制給input
本篇文章是對js獲取當前url中的參數(shù)值并復制給input的方法進行了詳細的分析介紹,需要的朋友參考下2013-06-06

