相關(guān)關(guān)鍵詞
關(guān)于我們
最新文章
- 拉動(dòng)懸浮于頂部的JS控制代碼
- 在JavaScript中構(gòu)建ArrayList示例代碼
- js使用for循環(huán)及if語句判斷多個(gè)一樣的name
- JavaScript中判斷原生函數(shù)檢查function是否是原生代碼
- jQuery CSS()方法改變現(xiàn)有的CSS樣式表
- JavaScript中判斷原生函數(shù)檢查function是否是原生代碼
- jQuery動(dòng)畫高級(jí)用法(上)——詳解animation中的.queue()函數(shù)
- python小技巧之批量抓取美女圖片
- JS中offsetTop、clientTop、scrollTop、offsetTop各屬性介紹
- JS獲取瀏覽器窗口大小 獲取屏幕,瀏覽器,網(wǎng)頁高度寬度
javascript 變量和作用域
今天學(xué)習(xí)了javascript 的變量和作用域的基本知識(shí),對(duì)于以前在開發(fā)中遇到的一些不懂的小問題也有了系統(tǒng)的認(rèn)識(shí),收獲還是比較多的。
【基本類型和引用類型】
ECMAScript 變量可能包含兩種不同數(shù)據(jù)類型的值:基本類型值和引用類型值。基本類型值指的是簡(jiǎn)單的數(shù)據(jù)段,而引用類型值指那些可能由多個(gè)值構(gòu)成的對(duì)象。我們常見的五種基本類型的值:Undefined、Null、Boolean、Number 和 String ,這五種基本數(shù)據(jù)類型是按值訪問的,因此可以操作保存在變量中的實(shí)際的值。引用類型的值是保存在內(nèi)存中的對(duì)象,也就是說不能夠直接操作對(duì)象的內(nèi)存空間,引用類型的值是按引用訪問的。注意:我們不能給基本類型的值添加屬性,例如以下代碼:
var name = 'name1';
name.age = 22;
console.log(name.age); // undefined
【復(fù)制變量值】
從一個(gè)變量向另一個(gè)變量復(fù)制基本類型值很引用類型值時(shí)存在不同的情況,如果從一個(gè)變量向另一個(gè)變量復(fù)制基本類型的值,會(huì)在變量對(duì)象上創(chuàng)建一個(gè)新值,然后把該值復(fù)制到為新變量分配的位置上,例如:
var num1 = 5;
var num2 = num1;
通過以上的復(fù)制方式,num1 中的 5 和 num2 中的 5 是完全獨(dú)立的,也就是說修改 num1 或者 num2 是不會(huì)影響到另外一個(gè)值的,我們參考如下的代碼:
var num1 = 5;
var num2 = num1;
console.log(num1,num2); // 5 5
num1 = 6;
console.log(num1,num2); // 6 5
下面的表格形象的展示的復(fù)制基本類型值的一個(gè)過程:
復(fù)制前的變量對(duì)象 復(fù)制后的變量對(duì)象
num2
5
(Number類型)
num1
5
(Number類型)
num1
5
(Number類型)
當(dāng)從一個(gè)變量向另一個(gè)變量復(fù)制引用類型的值的時(shí)候,同樣也會(huì)將存儲(chǔ)在變量對(duì)象中的值復(fù)制一份放到為新變量分配的空間中。但是這個(gè)值的副本實(shí)際上是一個(gè)指針,而這個(gè)指針指向存儲(chǔ)在堆中的一個(gè)對(duì)象。復(fù)制操作結(jié)束后,兩個(gè)變量引用的其實(shí)是一個(gè)值。因此,改變?nèi)我庖粋€(gè)變量都會(huì)影響到另外一個(gè)變量。例如以下代碼:
復(fù)制代碼
var per1 = new Object();
var per2 = per1;
per1.name = 'name1';
console.log(per1.name,per2.name); // name1 name1
per1.name = 'name2';
console.log(per1.name,per2.name); // name2 name2
per2.name = 'name3';
console.log(per1.name,per2.name); // name3 name3
復(fù)制代碼
下圖詳細(xì)的展示了保存在變量對(duì)象中和保存在堆中的對(duì)象之間的關(guān)系:
【傳遞參數(shù)】
ECMAScript 中所有函數(shù)的參數(shù)都是按值傳遞的,也就是說,把函數(shù)外部的值復(fù)制給函數(shù)內(nèi)部的參數(shù),就和把值從一個(gè)變量復(fù)制到另外一個(gè)變量一樣?;绢愋椭档膫鬟f如同基本類型變量的復(fù)制一樣,引用類型的傳遞如同引用類型變量的復(fù)制一樣。例如以下代碼:
復(fù)制代碼
function addNum(num){
num += 10;
return num;
}
var count = 20;
var result = addNum(count);
console.log(count,result); // 20 30
復(fù)制代碼
這里的函數(shù) addNum() 有一個(gè)參數(shù) num ,而參數(shù)實(shí)際上是函數(shù)的局部變量。在調(diào)用這個(gè)函數(shù)時(shí),變量 count 作為參數(shù)被傳遞給函數(shù),這個(gè)變量的值是20。于是,數(shù)值20被復(fù)制給參數(shù) num 。但是 num 的改變并不能影響 count 的值,所以 count 輸出的值仍然是20 。再舉一個(gè)例子:
function setName(obj){
obj.name = 'name5';
}
var newObj = new Object();
setName(newObj);
console.log(newObj.name); // name5
這段代碼看起來是在局部作用域中修改了 newObj 的 name 的值,在全局作用域也反映出來了,這樣的理解是錯(cuò)誤的。再看一段代碼:
復(fù)制代碼
function setName(obj){
obj.name = 'name6';
var obj = new Object();
obj.name = 'name7';
}
var newObj = new Object();
setName(newObj);
console.log(newObj.name); // name6
復(fù)制代碼
對(duì)比兩段代碼可以看出,如果 newObj 是按引用傳遞的,那么 newObj 的 name 屬性應(yīng)該是 name7 才對(duì),但是 name 屬性是 name6,這說明及時(shí)在函數(shù)內(nèi)部修改了參數(shù)的值,但原始的引用仍然保持未變。
【執(zhí)行環(huán)境和作用域】
執(zhí)行環(huán)境定義了變量或函數(shù)有權(quán)訪問的其他數(shù)據(jù),決定了他們各自的行為。全局執(zhí)行環(huán)境是最外圍的一個(gè)執(zhí)行環(huán)境,在Web瀏覽器中,全局執(zhí)行環(huán)境被認(rèn)為是 window 對(duì)象,因此所有的全局變量和函數(shù)都是作為 window 對(duì)象的屬性和方法創(chuàng)建的。每個(gè)函數(shù)都有自己的執(zhí)行環(huán)境。當(dāng)代碼在一個(gè)環(huán)境中執(zhí)行時(shí),會(huì)創(chuàng)建變量對(duì)象的一個(gè)作用域鏈。作用域鏈的用途,是保證對(duì)執(zhí)行環(huán)境有權(quán)訪問的所有變量和函數(shù)的有序訪問。作用域鏈的前端,時(shí)鐘都是當(dāng)前執(zhí)行的代碼所在環(huán)境的變量對(duì)象。如果這個(gè)環(huán)境是函數(shù),則將其活動(dòng)對(duì)象作為變量對(duì)象。作用域鏈中的下一個(gè)變量對(duì)象來自包含(外部)環(huán)境,再下一個(gè)變量對(duì)象則來自下一個(gè)包含環(huán)境。全局執(zhí)行環(huán)境的變量對(duì)象始終都是作用域鏈的最后一個(gè)對(duì)象。標(biāo)識(shí)符解析是沿著作用域鏈一級(jí)一級(jí)的搜索標(biāo)識(shí)符的過程。請(qǐng)看如下代碼:
復(fù)制代碼
var color = 'blue';
function changeColor(){
if(color == 'blue'){
color = 'red';
}
else{
color = 'blue';
}
}
changeColor();
console.log(color); // red
復(fù)制代碼
函數(shù) changeColor() 的作用域包含兩個(gè)對(duì)象:它自己的變量對(duì)象(其中定義著 arguments 對(duì)象)和全局環(huán)境的變量對(duì)象。當(dāng) changeColor 在執(zhí)行的時(shí)候,在自己的作用域中并沒有找到 color ,于是便到全局環(huán)境中找,找到了 color 的值為 blue ,然后按照 changeColor() 函數(shù)的規(guī)則將 color 的值設(shè)置為 red 。再看一段更加詳細(xì)的代碼:
復(fù)制代碼
//這里只能訪問 color
var color = 'blue';
function changeColor(){ //這里可以訪問 color 、newColor ,但是不能訪問 temColor
var newColor = 'red';
function swapColor(){ //這里可以訪問 color 、newColor 和 temColor
var temColor = newColor;
newColor = color;
color = temColor;
}
swapColor();
console.log(color,newColor); //red blue
}
function showColor(){
console.log(color); //blue
}
showColor();
changeColor();
復(fù)制代碼
代碼的內(nèi)容自己體會(huì)一下,這里不做詳細(xì)的解釋。
【沒有塊級(jí)作用域】
看如下的代碼:
for(var i = 0;i < 10;i ++){
i += 1;
}
console.log(i); // 10
對(duì)于有塊級(jí)作用域的語言來說, for 語句初始化變量的表達(dá)式所定義的變量,只會(huì)存在于循環(huán)的環(huán)境之中。在 javascript 中, i 并會(huì)在 for 循環(huán)執(zhí)行結(jié)束后被銷毀,反而被添加到了當(dāng)前的執(zhí)行環(huán)境(全局環(huán)境)中。
1.聲明變量
使用 var 聲明的變量會(huì)自動(dòng)被添加到最接近的環(huán)境中。在函數(shù)內(nèi)部,最接近的環(huán)境就是函數(shù)的局部環(huán)境。請(qǐng)看如下代碼:
復(fù)制代碼
function addNum(num1,num2){
var num = num1 + num2;
return num;
}
var result = addNum(10,20);
console.log(result); // 30
console.log(num); // num is not defined
復(fù)制代碼
以上代碼如果不使用 var 聲明 num 的話是不會(huì)導(dǎo)致錯(cuò)誤的,例如:
復(fù)制代碼
function addNum(num1,num2){
num = num1 + num2;
return num;
}
var result = addNum(10,20);
console.log(result); // 30
console.log(num); // 30
復(fù)制代碼
2.查詢標(biāo)識(shí)符
當(dāng)在某個(gè)環(huán)境中為了讀取或?qū)懭攵靡粋€(gè)標(biāo)識(shí)符時(shí),必須通過搜索來確定該標(biāo)識(shí)符實(shí)際代表什么。搜索過程從作用域鏈的前端開始,向上逐級(jí)查詢與給定名字匹配的標(biāo)識(shí)符。如果在局部環(huán)境中找到該標(biāo)識(shí)符,搜索過程停止,變量就緒。如果在局部變量中沒有找到該變量名,則繼續(xù)沿作用域鏈向上搜索。搜索過程會(huì)一致追溯到全局環(huán)境變量。如果在全局環(huán)境變量也沒有找到該標(biāo)識(shí)符,說明該變量尚未定義。請(qǐng)查看以下代碼:
var color = 'blue';
function getColor(){
return color;
}
console.log(getColor()); // blue
getaColor() 在搜索局部變量的時(shí)候沒有找到 color ,而函數(shù)執(zhí)行語句是一定要返回一個(gè) color ,與是便到全局環(huán)境變量中去搜索,找到了 color 。需要注意的是,搜索的過程中如果存在一個(gè)局部變量的定義,則搜索會(huì)自動(dòng)停止,不再進(jìn)入另一個(gè)變量對(duì)象。也就是說,如果局部環(huán)境存在著同名標(biāo)識(shí)符,就不會(huì)使用位于父環(huán)境的標(biāo)識(shí)符,例如以下代碼:
var color = 'blue';
function getColor(){
var color = 'red';
return color;
}
console.log(getColor()); // red
作用域鏈對(duì)于理解閉包的概念至關(guān)重要,還忘能夠加深理解。