首先要理解js中作用域的概念
作用域:指的是一個(gè)變量的作用范圍
1.全局作用域
直接寫在script中的js代碼,在js中,萬物皆對(duì)象,都在全局作用域,全局作用域在頁面打開時(shí)創(chuàng)建,在全局作用域中有一個(gè)全局對(duì)象window,它代表是一個(gè)瀏覽器的窗口
它由瀏覽器創(chuàng)建可以直接使用,在全局作用域中,創(chuàng)建的對(duì)象都可以都可以作為window對(duì)象的屬性保存,在任何地方都可以調(diào)用
2.函數(shù)作用域
調(diào)用函數(shù)時(shí)創(chuàng)建函數(shù)作用域,函數(shù)執(zhí)行完畢后,函數(shù)作用域銷毀,每調(diào)用一次函數(shù)會(huì)創(chuàng)建一個(gè)新的函數(shù)作用域他們之間是相互獨(dú)立的,函數(shù)中可以訪問到全局作用域的變量,反之不行。當(dāng)在函數(shù)作用域中操作對(duì)象,如果有,則使用,如果沒有則向其上一個(gè)作用域(不是指的是全局作用域)找,直到找到全局作用域無論在那個(gè)作用域,都有變量聲明提前現(xiàn)象,在函數(shù)中不用var聲明的變量都會(huì)設(shè)置為全局變量,形參相當(dāng)于在函數(shù)作用域里聲明變量
var定義的變量可被更改,如果不初始化而直接使用也不會(huì)報(bào)錯(cuò),var聲明的變量會(huì)得到提升,其余兩個(gè)不存在這種情況,即必須先聲明再賦值
let定義的變量和var類似,但作用域在當(dāng)前聲明的范圍內(nèi)
const定義的變量只可初始化一次且作用域內(nèi)不可被更改,使用前必須初始化
1.var的變量提升
js和其他語言一樣,都要經(jīng)歷編譯和執(zhí)行階段。而js在編譯階段的時(shí)候,會(huì)搜集所有的變量聲明并且提前聲明變量,而不會(huì)改變其他語句的順序,因此,在編譯階段的時(shí)候,第一步就已經(jīng)執(zhí)行了,而第二步則是在執(zhí)行階段執(zhí)行到該語句的時(shí)候才執(zhí)行
經(jīng)典案例
var即可用于函數(shù)外,亦可用于函數(shù)內(nèi),這就涉及到全局變量與局部變量的問題,
全局變量如何聲明:
在函數(shù)外聲明的變量就是全局變量,反之,在函數(shù)內(nèi)聲明的變量就是局部變量,
作用域:全局變量無論在函數(shù)內(nèi),還是函數(shù)外,都可訪問到;
局部變量只能在函數(shù)內(nèi)有效,函數(shù)外部訪問不到該變量及說對(duì)應(yīng)的變量值
<script> var a = 10; function change() { console.log(a); var a = 7; //變量提升原因 例子1 } change() //輸出為undefine console.log(a);//輸出為10 </script>
<script> var a = 10; function change() { a = 7; //改變了全局變量a的值 } change(); console.log(a);//輸出為7 </script> --------------------- <script> var a = 10; function change() { var a = 7; //作用域的原因,a屬于函數(shù)作用域。 } change(); console.log(a);//輸出為10 輸出的a是全局區(qū)域中的a,因?yàn)榫植孔兞恐荒茉诤瘮?shù)內(nèi)有效,函數(shù)外部訪問不到該變量及說對(duì)應(yīng)的變量值 </script>
let是塊級(jí)作用域,函數(shù)內(nèi)部使用let定義后,對(duì)函數(shù)外部無影響
ES6 新增了let命令,用來聲明變量。它的用法類似于var,但是所聲明的變量,只在let命令所在的代碼塊內(nèi)有效。
{ let a = 10; var b = 1; } a // ReferenceError: a is not defined. b // 1 不可以{ let a = 1; let = 3;重復(fù)定義在一個(gè)塊級(jí)作用域 }
for循環(huán)的計(jì)數(shù)器,就很合適使用let命令
for (let i = 0; i < 10; i++) { // ... } console.log(i); // ReferenceError: i is not defined
暫時(shí)性死區(qū)
var tmp = 123; if (true) { tmp = 'abc'; // ReferenceError//下面定義了let tmp 上面只要這種操作就是暫時(shí)性死區(qū),為了讓我們編碼嚴(yán)格 const也是 let tmp; }
為什么用塊級(jí)作用域?
1.例子1的變量提升,2就是for循環(huán)中的i
塊級(jí)作用域
function f1() { let n = 5; if (true) { let n = 10; } console.log(n); // 5 如果是var,的話會(huì)輸出10 }
const聲明一個(gè)只讀的常量。一旦聲明,常量的值就不能改變。
對(duì)于const來說,只聲明不賦值,就會(huì)報(bào)錯(cuò)。
const的作用域與let命令相同:只在聲明所在的塊級(jí)作用域內(nèi)有效。
const命令聲明的常量也是不提升,同樣存在暫時(shí)性死區(qū),只能在聲明的位置后面使用。
const聲明的常量,也與let一樣不可重復(fù)聲明。
本質(zhì)
const實(shí)際上保證的,并不是變量的值不得改動(dòng),而是變量指向的那個(gè)內(nèi)存地址所保存的數(shù)據(jù)不得改動(dòng)。對(duì)于簡(jiǎn)單類型的數(shù)據(jù)(數(shù)值、字符串、布爾值),值就保存在變量指向的那個(gè)內(nèi)存地址,因此等同于常量。但對(duì)于復(fù)合類型的數(shù)據(jù)(主要是對(duì)象和數(shù)組),變量指向的內(nèi)存地址,保存的只是一個(gè)指向?qū)嶋H數(shù)據(jù)的指針,const只能保證這個(gè)指針是固定的(即總是指向另一個(gè)固定的地址),至于它指向的數(shù)據(jù)結(jié)構(gòu)是不是可變的,就完全不能控制了。因此,將一個(gè)對(duì)象聲明為常量必須非常小心。
const foo = {}; // 為 foo 添加一個(gè)屬性,可以成功 foo.prop = 123; foo.prop // 123 // 將 foo 指向另一個(gè)對(duì)象,就會(huì)報(bào)錯(cuò) foo = {}; // TypeError: "foo" is read-only
---------------------
覺得寫的還可以的朋友,請(qǐng)點(diǎn)贊加關(guān)注哦
如果文章中有疏忽寫錯(cuò)的或者你不理解的還請(qǐng)?jiān)u論區(qū)內(nèi)交流哦