天天看點

JavaScript 作用域、變量提升

JavaScript 作用域

    • JavaScript 作用域
    • JavaScript 局部作用域
    • JavaScript 全局變量
    • JavaScript 變量生命周期
    • 函數參數
    • HTML 中的全局變量
    • ES6中的變量和作用域
      • 通過let和const決定塊作用域
      • const建立不可變的變量
    • JavaScript 變量提升
    • JavaScript 初始化不會提升
    • 在頭部聲明你的變量

你越是認真生活,你的生活就會越美好

——弗蘭克·勞埃德·萊特

《人生果實》經典語錄

JavaScript 作用域

作用域

可通路變量

的集合。

在 JavaScript 中,

對象和函數

同樣也是變量。

在 JavaScript 中,

作用域為可通路變量,對象,函數的集合

JavaScript

函數作用域

: 作用域在函數内修改。

JavaScript 局部作用域

變量在

函數内聲明

,變量為局部作用域。

局部變量:

隻能在函數内部通路

// 此處不能調用 carName 變量
function myFunction() {
    var carName = "Volvo";
    // 函數内可調用 carName 變量
}
           

因為

局部變量

隻作用于

函數内

,是以

不同的函數

可以使用

相同名稱的變量

局部變量

在函數開始執行時建立,

函數執行完後

局部變量會

自動銷毀

JavaScript 全局變量

變量在

函數外

定義,即為

全局變量

全局變量有

全局作用域

: 網頁中

所有腳本

和函數均可使用。

var carName = " Volvo";
 
// 此處可調用 carName 變量
function myFunction() {
    // 函數内可調用 carName 變量
}
           

如果變量在

函數内沒有聲明

(沒有使用 var 關鍵字),

該變量為全局變量

以下執行個體中 carName 在函數内,但是為全局變量。

function myFunction() {
    carName = "Volvo";
    // 此處可調用 carName 變量
}
myFunction()
// 此處可調用 carName 變量  前提是myFunction函數執行過
console.log(carName) // Volvo
           

JavaScript 變量生命周期

JavaScript 變量生命周期

在它

聲明時初始化

局部變量

函數執行完畢後銷毀

全局變量

頁面關閉後銷毀

函數參數

函數參數

隻在

函數内

起作用,是

局部變量

HTML 中的全局變量

在 HTML 中, 全局變量是 window 對象: 所有資料變量都屬于 window 對象。

function myFunction() {
    carName = "Volvo";
}
myFunction()

//此處可使用 window.carName
console.log(window.carName)
           

PS:

你的全局變量,或者函數,可以覆寫 window 對象的變量或者函數。

局部變量,包括 window 對象可以覆寫全局變量和函數。

ES6中的變量和作用域

通過let和const決定塊作用域

let

const

建立的變量

隻在塊作用域中

有效。它們隻存于包含它們的塊中。下面示範的代碼,通過let在if語句塊中聲明一個tmp變量。這個變量僅在if語句中有效。

function func() { 
	if (true) { 
		let tmp = 123; 
		console.log(tmp); // => 123 
	} 
}
func() // 123
console.log(tmp); // => ReferenceError: tmp is not defined
           

相比之下,

var聲明的變量

作用域的範圍是

函數範圍内

的:

function func() {
	console.log(tmp) // undefined 變量聲明提升 還沒指派
	if (true) {
		var tmp = 123
		console.log(tmp) // 123
	}
	console.log(tmp) // 123
}
func()
console.log(tmp) // Uncaught ReferenceError: tmp is not defined
           

塊作用域意味着你可在有函數内有變量的陰影。

function func() {
    let foo = 5;
    console.log(foo) // 5
    if(true) {
        let foo = 10;
        console.log(foo) // 10
    }
    console.log(foo) // 5
}
func()
           

const建立不可變的變量

let

建立的變量是可變的:

let foo = 'abc'
foo = 'def'
console.log(foo) // def
           

const

建立的是變量是一個

常量

,這個變量是

不可變

的:

const foo = 'abc'
foo = 'def' // Uncaught TypeError: Assignment to constant variable.
           

如果一個常量指的是一個

對象

,那麼

const并不影響常量本身的值

是否是可變的,因為它總是指向那個對象,但是對象本身仍然是可以被改變的。

const obj = {}
obj.prop = 123
console.log(obj.prop) // 123
console.log(obj) // {prop: 123}
obj = {} // Uncaught TypeError: Assignment to constant variable.
           

如果你想讓

obj

真正成為一個

常量

,你必須

當機它的值

const obj = Object.freeze({}); 
obj.prop = 123;
console.log(obj) // {}
           

也就是說,如果

const定義

的常量指向的是一個對象。這個時候,它實際上指向的是目前對象的位址。這個位址是在棧裡面的,而這個真實的對象是在堆棧裡面的。是以,我們使用const定義這個對象後,是可以改變對象的内容的。但是

這個位址是不可以改變的

。意思也就是不可以給這個對象重新指派,比如

const obj= {}, obj = {}

,即使是這樣,obj好像什麼也沒有改變,但還是錯誤的。

然而在

普通模式

下,并沒有報錯,而obj.name = 'abc’這是完全可以的。這跟JavaScript存儲引用對象的值的方式有密切的關系。

const obj = Object.freeze({})
const newObj = {}
obj.name = 'w3cplus'
newObj.name = 'damo'; 

console.log(obj) // {}
console.log(newObj) // {name: "damo"}
           

使用Babel把上面ES6的代碼編譯成ES5代碼:

'use strict';
var obj = Ob
           

JavaScript 變量提升

  • JavaScript 中,

    函數及變量的聲明

    都将被

    提升到函數的最頂部

  • JavaScript 中,

    變量可以在使用後聲明

    ,也就是

    變量可以先使用再聲明

  • 不存在變量提升

以下兩個執行個體将獲得相同的結果:

例子1

x = 5; // 變量 x 設定為 5

elem = document.getElementById("demo"); // 查找元素
elem.innerHTML = x;                     // 在元素中顯示 x

var x; // 聲明 x
           

例子2

var x; // 聲明 x
x = 5; // 變量 x 設定為 5

console.log(x)  // 5
           

要了解以上執行個體就需要了解 “

hoisting(變量提升)

”。

變量提升

函數聲明

變量聲明

總是會被解釋器悄悄地

被"提升"到方法體的最頂部

不存在變量提升

new Foo() // Uncaught ReferenceError: Foo is not defined
class Foo {}
           

JavaScript 初始化不會提升

JavaScript 隻有聲明的變量會提升,初始化的不會。

執行個體1

var x = 5; // 初始化 x
var y = 7; // 初始化 y

console.log(x) // 5
console.log(y) // 7
           

執行個體2

var x = 5; // 初始化 x

console.log(x) // 5
console.log(y) // undefined

var y = 7; // 初始化 y
           

執行個體 2 的 y 輸出了 undefined,這是因為變量聲明 (var y) 提升了,但是初始化(y = 7) 并不會提升,是以 y 變量是一個未定義的變量。

執行個體 2 類似以下代碼:

var x = 5; // 初始化 x
var y;     // 聲明 y

console.log(x) // 5
console.log(y) // undefined

y = 7;    // 設定 y 為 7
           

在頭部聲明你的變量

對于大多數程式員來說并不知道

JavaScript 變量提升

如果程式員不能很好的了解變量提升,他們寫的程式就容易出現一些問題。

為了避免這些問題,通常我們

在每個作用域開始前聲明

這些變量,這也是正常的 JavaScript 解析步驟,易于我們了解。

謝謝你閱讀到了最後~

期待你關注、收藏、評論、點贊~

讓我們一起 變得更強

參考

JavaScript 作用域

推薦閱讀

了解js中this的指向(幾條規則加例子+call,apply,bind改變this指向)

繼續閱讀