JavaScript內(nèi)核之基本概念
更新時間:2011年10月21日 20:32:06 作者:
本文將聚焦于JavaScript中的基本概念,這些概念與傳統(tǒng)語言有比較大的不同,因此單獨列出一章來做專門描述,理解本章的概念對書中后續(xù)章節(jié)的概念,代碼的行為等會有很大的幫助,讀者不妨花比較大的時間在本章,即使你對JavaScript已經(jīng)比較熟悉,也建議通讀本文
本章主要講述JavaScript中的數(shù)據(jù)類型(基本類型與引用類型),變量(包括變量的作用域),操作符(主要是一些較為常見,但是不容易從字面上理解的操作符)。由于JavaScript中的“一切皆對象”,在掌握了這些基本的概念之后,讀者就可以較為輕松的理解諸如作用域,調(diào)用對象,閉包,currying等等較難理解的概念了。
數(shù)據(jù)類型
有程序設(shè)計經(jīng)驗的讀者肯定知道,在C或者Java這樣的語言中,數(shù)據(jù)是有類型的,比如用以表示用戶名的屬性是字符串,而一個雇員的年齡則是一個數(shù)字,表示UI上的一個開關(guān)按鈕的數(shù)據(jù)模型則為布爾值等等,對數(shù)字可能還可以細分為浮點數(shù),整型數(shù),整型數(shù)又可能分為長整型和短整型,總而言之,它們都表示語言中的數(shù)據(jù)的值的類型。
JavaScript中的數(shù)據(jù)類型分為兩種:基本數(shù)據(jù)類型和對象類型,其中對象類型包含對象,數(shù)組,以及函數(shù)(事實上,函數(shù),數(shù)組等也都是對象,這個在后邊的章節(jié)詳述)。
1.1.1 基本數(shù)據(jù)類型
在JavaScript中,包含三種基本的數(shù)據(jù)類型,字符串(String),數(shù)值(Number),布爾值(boolean),下面是一些簡單的例子:
我們可以分別查看變量的值及變量的類型:
print(str);
print(i);
print(f);
print(b);
print(typeof str);
print(typeof i);
print(typeof f);
print(typeof b);
注意,在此處使用的print()函數(shù)為rhino解釋器的頂層對象的方法,可以用來打印字符串,通常情況下,在客戶端,程序員多使用alert()進行類似的動作,alert()是瀏覽器中JavaScript解釋器的頂層對象(window)的一個方法。
Hello, world
10
2.3
true
string
number
number
Boolean
在JavaScript中,所有的數(shù)字,不論是整型浮點,都屬于“數(shù)字”基本類型。typeof是一個一元的操作符,在本章的另外一個小節(jié)會專門講到。
1.1.2 對象類型
這里提到的對象不是對象本身,而是指一種類型,我們在第三章會對對象進行詳細的討論,此處的對象包括,對象(屬性的集合,即鍵值的散列表),數(shù)組(有序的列表),函數(shù)(包含可執(zhí)行的代碼)。
對象類型是一種復(fù)合的數(shù)據(jù)類型,其基本元素由基本數(shù)據(jù)類型組成,當然不限于基本類型,比如對象類型中的值可以是其他的對象類型實例,我們通過例子來說明:
可以看到,對象具有屬性,如obj.str, obj.num,這些屬性的值可以是基本類型,事實上還可以更復(fù)雜,我們來看看他們的類型:
print(typeof obj);
print(typeof array);
print(typeof func);
//將打印出
object
object
function
讀者可能會對print(typeof array)打印出object感到奇怪,事實上,對象和數(shù)組的界限并不那么明顯(事實上它們是屬于同一類型的),但是他們的行為卻非常不同,本書的后續(xù)章節(jié)將兩個重要的數(shù)據(jù)類型做了分別介紹。
2.1.3 兩者之間的轉(zhuǎn)換
類似與Java中基本數(shù)據(jù)類型的自動裝箱拆箱,JavaScript也有類似的動作,基本數(shù)據(jù)類型在做一些運算時,會臨時包裝一個對象,做完運算后,又自動釋放該對象。我們可以通過幾個例子來說明:
str為一個字符串,通過typeof運算符可知其type為”string”,而:
可知,str2的type為”object”,即這兩者并不相同,那么為什么可以使用str.length來的到str的長度呢?事實上,當使用str.length時,JavaScript會自動包裝一個臨時的String對象,內(nèi)容為str的內(nèi)容,然后獲取該對象的length屬性,最后,這個臨時的對象將被釋放。
而將對象轉(zhuǎn)換為基本類型則是通過這樣的方式:通過調(diào)用對象的valueOf()方法來取得對象的值,如果和上下文的類型匹配,則使用該值。如果valueOf取不到值的話,則需要調(diào)用對象的toString()方法,而如果上下文為數(shù)值型,則又需要將此字符串轉(zhuǎn)換為數(shù)值。由于JavaScript是弱類型的,所以JavaScript引擎需要根據(jù)上下文來“猜測”對象的類型,這就使得JavaScript的效率比編譯型的語言要差一些。
valueOf()的作用是,將一個對象的值轉(zhuǎn)換成一種合乎上下文需求的基本類型,toString()則名副其實,可以打印出對象對應(yīng)的字符串,當然前提是你已經(jīng)“重載”了Object的toString()方法。
事實上,這種轉(zhuǎn)換規(guī)則會導(dǎo)致很多的問題,比如,所有的非空對象,在布爾值環(huán)境下,都會被轉(zhuǎn)成true,比如:
function convertTest(){
if(new Boolean(false) && new Object() &&
new String("") && new Array()){
print("convert to boolean")
}
}
convertTest();//convert to Boolean
初學(xué)者容易被JavaScript中的類型轉(zhuǎn)換規(guī)則搞暈掉,很多情況下會覺得那種寫法看著非常別扭,其實只需要掌握了規(guī)則,這些古怪的寫法會大大的提高代碼的性能,我們通過例子來學(xué)習(xí)這些規(guī)則:
var x = 3;
var y = x + "2";// => 32
var z = x + 2;// => 5
print(y);
print(z);
通??梢栽贘S代碼中發(fā)現(xiàn)這樣的代碼:
這種寫法事實上具有更深層次的含義:
應(yīng)該注意到,datamodel.item是一個對象(字符串,數(shù)字等),而if需要一個boolean型的表達式,所以這里進行了類型轉(zhuǎn)換。在JavaScript中,如果上下文需要boolean型的值,則引擎會自動將對象轉(zhuǎn)換為boolean類型。轉(zhuǎn)換規(guī)則為,如果該對象非空,則轉(zhuǎn)換為true,否則為false.因此我們可以采取這種簡寫的形式。
而在傳統(tǒng)的編程語言(強類型)中,我們則需要:
2.1.4類型的判斷
前面講到JavaScript特性的時候,我們說過,JavaScript是一個弱類型的語言,但是有時我們需要知道變量在運行時的類型,比如,一個函數(shù)的參數(shù)預(yù)期為另一個函數(shù):
當調(diào)用handleMessage的函數(shù)傳遞的handle不是一個函數(shù)則JavaScript引擎會報錯,因此我們有必要在調(diào)用之前進行判斷:
但是,typeof并不總是有效的,比如下面這種情況:
運行結(jié)果顯示,對象obj和數(shù)組array的typeof值均為”object”,這樣我們就無法準確判斷了,這時候,可以通過調(diào)用instanceof來進行進一步的判斷:
print(obj instanceof Array);//false
print(array instanceof Array);//true
第一行代碼返回false,第二行則返回true。因此,我們可以將typeof操作符和instanceof操作符結(jié)合起來進行判斷。
2.2 變量
變量,即通過一個名字將一個值關(guān)聯(lián)起來,以后通過變量就可以引用到該值,比如:
當我們下一次要引用”Hello, Wrold”這個串進行某項操作時,我們只需要使用變量str即可,同樣,我們可以用10*num來表示10*2.345。變量的作用就是將值“存儲”在這個變量上。
2.2.1基本類型和引用類型
在上一小節(jié),我們介紹了JavaScript中的數(shù)據(jù)類型,其中基本類型如數(shù)字,布爾值,它們在內(nèi)存中都有固定的大小,我們通過變量來直接訪問基本類型的數(shù)據(jù)。而對于引用類型,如對象,數(shù)組和函數(shù),由于它們的大小在原則上是不受任何限制的,故我們通過對其引用的訪問來訪問它們本身,引用本身是一個地址,即指向真實存儲復(fù)雜對象的位置。
基本類型和引用類型的區(qū)別是比較明顯的,我們來看幾個例子:
運行結(jié)果如下:
1
1
2
1
這樣的運行結(jié)果應(yīng)該在你的意料之內(nèi),沒有什么特別之處,我們再來看看引用類型的例子,由于數(shù)組的長度非固定,可以動態(tài)增刪,因此數(shù)組為引用類型:
引用指向的是地址,也就是說,引用不會指向引用本身,而是指向該引用所對應(yīng)的實際對象。因此通過修改array指向的數(shù)組,則arrayRef指向的是同一個對象,因此運行效果如下:
1,2,3,4,5,6
2.2.2變量的作用域
變量被定義的區(qū)域即為其作用域,全局變量具有全局作用域;局部變量,比如聲明在函數(shù)內(nèi)部的變量則具有局部作用域,在函數(shù)的外部是不能直接訪問的。比如:
應(yīng)該注意的是,在函數(shù)內(nèi)var關(guān)鍵字是必須的,如果使用了變量而沒有寫var關(guān)鍵字,則默認的操作是對全局對象的,比如:
由于函數(shù)func中使用variable而沒有關(guān)鍵字var,則默認是對全局對象variable屬性做的操作(修改variable的值為in),因此此段代碼會打印:
in
in
2.3運算符
運算符,通常是容易被忽略的一個內(nèi)容,但是一些比較古怪的語法現(xiàn)象仍然可能需要用到運算符的結(jié)合率或者其作用來進行解釋,JavaScript中,運算符是一定需要注意的地方,有很多具有JS編程經(jīng)驗的人仍然免不了被搞得暈頭轉(zhuǎn)向。
我們在這一節(jié)主要講解這樣幾個運算符:
2.3.1中括號運算符([])
[]運算符可用在數(shù)組對象和對象上,從數(shù)組中按下標取值:
而[]同樣可以作用于對象,一般而言,對象中的屬性的值是通過點(.)運算符來取值,如:
但是考慮到這樣一種情況,我們在遍歷一個對象的時候,對其中的屬性的鍵(key)是一無所知的,我們怎么通過點(.)來訪問呢?這時候我們就可以使用[]運算符:
運行結(jié)果如下:
field:slef
printInfo:function (){
print(this.field);
}
2.3.2點運算符(.)
點運算符的左邊為一個對象(屬性的集合),右邊為屬性名,應(yīng)該注意的是右邊的值除了作為左邊的對象的屬性外,同時還可能是它自己的右邊的值的對象:
這個例子中,outter作為object的屬性,同時又是printInnerText()的對象。
2.3.3 == 和 === 以及 != 和 !==
運算符==讀作相等,而運算符===則讀作等同。這兩種運算符操作都是在JavaScript代碼中經(jīng)常見到的,但是意義則不完全相同,簡而言之,相等操作符會對兩邊的操作數(shù)做類型轉(zhuǎn)換,而等同則不會。我們還是通過例子來說明:
print(1 == true);
print(1 === true);
print("" == false);
print("" === false);
print(null == undefined);
print(null === undefined);
運行結(jié)果如下:
相等和等同運算符的規(guī)則分別如下:
相等運算符
如果操作數(shù)具有相同的類型,則判斷其等同性,如果兩個操作數(shù)的值相等,則返回true(相等),否則返回false(不相等).
如果操作數(shù)的類型不同,則按照這樣的情況來判斷:
◆ null和undefined相等
◆ 其中一個是數(shù)字,另一個是字符串,則將字符串轉(zhuǎn)換為數(shù)字,在做比較
◆ 其中一個是true,先轉(zhuǎn)換成1(false則轉(zhuǎn)換為0)在做比較
◆ 如果一個值是對象,另一個是數(shù)字/字符串,則將對象轉(zhuǎn)換為原始值(通過toString()或者valueOf()方法)
◆ 其他情況,則直接返回false
等同運算符
如果操作數(shù)的類型不同,則不進行值的判斷,直接返回false
如果操作數(shù)的類型相同,分下列情況來判斷:
◆ 都是數(shù)字的情況,如果值相同,則兩者等同(有一個例外,就是NaN,NaN與其本身也不相等),否則不等同
◆ 都是字符串的情況,與其他程序設(shè)計語言一樣,如果串的值不等,則不等同,否則等同
◆ 都是布爾值,且值均為true/false,則等同,否則不等同
◆ 如果兩個操作數(shù)引用同一個對象(數(shù)組,函數(shù)),則兩者完全等同,否則不等同
◆ 如果兩個操作數(shù)均為null/undefined,則等同,否則不等同
比如:
會返回:
true
true
再來看一個對象的例子:
返回值為:
true
false
obj1是一個對象,而obj2是一個結(jié)構(gòu)與之完全不同的字符串,而如果用相等操作符來判斷,則兩者是完全相同的,因為obj1重載了頂層對象的toString()方法。
而!=不等和!==不等同,則與==/!==相反。因此,在JavaScript中,使用相等/等同,不等/不等同的時候,一定要注意類型的轉(zhuǎn)換,這里推薦使用等同/不等同來進行判斷,這樣可以避免一些難以調(diào)試的bug。
數(shù)據(jù)類型
有程序設(shè)計經(jīng)驗的讀者肯定知道,在C或者Java這樣的語言中,數(shù)據(jù)是有類型的,比如用以表示用戶名的屬性是字符串,而一個雇員的年齡則是一個數(shù)字,表示UI上的一個開關(guān)按鈕的數(shù)據(jù)模型則為布爾值等等,對數(shù)字可能還可以細分為浮點數(shù),整型數(shù),整型數(shù)又可能分為長整型和短整型,總而言之,它們都表示語言中的數(shù)據(jù)的值的類型。
JavaScript中的數(shù)據(jù)類型分為兩種:基本數(shù)據(jù)類型和對象類型,其中對象類型包含對象,數(shù)組,以及函數(shù)(事實上,函數(shù),數(shù)組等也都是對象,這個在后邊的章節(jié)詳述)。
1.1.1 基本數(shù)據(jù)類型
在JavaScript中,包含三種基本的數(shù)據(jù)類型,字符串(String),數(shù)值(Number),布爾值(boolean),下面是一些簡單的例子:
復(fù)制代碼 代碼如下:
var str = "Hello, world";//字符串
var i = 10;//整型數(shù)
var f = 2.3;//浮點數(shù)
var b = true;//布爾值
var i = 10;//整型數(shù)
var f = 2.3;//浮點數(shù)
var b = true;//布爾值
我們可以分別查看變量的值及變量的類型:
復(fù)制代碼 代碼如下:
print(str);
print(i);
print(f);
print(b);
print(typeof str);
print(typeof i);
print(typeof f);
print(typeof b);
注意,在此處使用的print()函數(shù)為rhino解釋器的頂層對象的方法,可以用來打印字符串,通常情況下,在客戶端,程序員多使用alert()進行類似的動作,alert()是瀏覽器中JavaScript解釋器的頂層對象(window)的一個方法。
Hello, world
10
2.3
true
string
number
number
Boolean
在JavaScript中,所有的數(shù)字,不論是整型浮點,都屬于“數(shù)字”基本類型。typeof是一個一元的操作符,在本章的另外一個小節(jié)會專門講到。
1.1.2 對象類型
這里提到的對象不是對象本身,而是指一種類型,我們在第三章會對對象進行詳細的討論,此處的對象包括,對象(屬性的集合,即鍵值的散列表),數(shù)組(有序的列表),函數(shù)(包含可執(zhí)行的代碼)。
對象類型是一種復(fù)合的數(shù)據(jù)類型,其基本元素由基本數(shù)據(jù)類型組成,當然不限于基本類型,比如對象類型中的值可以是其他的對象類型實例,我們通過例子來說明:
復(fù)制代碼 代碼如下:
var str = "Hello, world";
var obj = new Object();
obj.str = str;
obj.num = 2.3;
var array = new Array("foo", "bar", "zoo");
var func = function(){
print("I am a function here");
}
var obj = new Object();
obj.str = str;
obj.num = 2.3;
var array = new Array("foo", "bar", "zoo");
var func = function(){
print("I am a function here");
}
可以看到,對象具有屬性,如obj.str, obj.num,這些屬性的值可以是基本類型,事實上還可以更復(fù)雜,我們來看看他們的類型:
復(fù)制代碼 代碼如下:
print(typeof obj);
print(typeof array);
print(typeof func);
//將打印出
object
object
function
讀者可能會對print(typeof array)打印出object感到奇怪,事實上,對象和數(shù)組的界限并不那么明顯(事實上它們是屬于同一類型的),但是他們的行為卻非常不同,本書的后續(xù)章節(jié)將兩個重要的數(shù)據(jù)類型做了分別介紹。
2.1.3 兩者之間的轉(zhuǎn)換
類似與Java中基本數(shù)據(jù)類型的自動裝箱拆箱,JavaScript也有類似的動作,基本數(shù)據(jù)類型在做一些運算時,會臨時包裝一個對象,做完運算后,又自動釋放該對象。我們可以通過幾個例子來說明:
復(fù)制代碼 代碼如下:
var str = "JavaScript Kernal";
print(str.length);//打印17
print(str.length);//打印17
str為一個字符串,通過typeof運算符可知其type為”string”,而:
復(fù)制代碼 代碼如下:
var str2 = new String("JavaScript Kernal");
print(typeof str2);
print(typeof str2);
可知,str2的type為”object”,即這兩者并不相同,那么為什么可以使用str.length來的到str的長度呢?事實上,當使用str.length時,JavaScript會自動包裝一個臨時的String對象,內(nèi)容為str的內(nèi)容,然后獲取該對象的length屬性,最后,這個臨時的對象將被釋放。
而將對象轉(zhuǎn)換為基本類型則是通過這樣的方式:通過調(diào)用對象的valueOf()方法來取得對象的值,如果和上下文的類型匹配,則使用該值。如果valueOf取不到值的話,則需要調(diào)用對象的toString()方法,而如果上下文為數(shù)值型,則又需要將此字符串轉(zhuǎn)換為數(shù)值。由于JavaScript是弱類型的,所以JavaScript引擎需要根據(jù)上下文來“猜測”對象的類型,這就使得JavaScript的效率比編譯型的語言要差一些。
valueOf()的作用是,將一個對象的值轉(zhuǎn)換成一種合乎上下文需求的基本類型,toString()則名副其實,可以打印出對象對應(yīng)的字符串,當然前提是你已經(jīng)“重載”了Object的toString()方法。
事實上,這種轉(zhuǎn)換規(guī)則會導(dǎo)致很多的問題,比如,所有的非空對象,在布爾值環(huán)境下,都會被轉(zhuǎn)成true,比如:
復(fù)制代碼 代碼如下:
function convertTest(){
if(new Boolean(false) && new Object() &&
new String("") && new Array()){
print("convert to boolean")
}
}
convertTest();//convert to Boolean
初學(xué)者容易被JavaScript中的類型轉(zhuǎn)換規(guī)則搞暈掉,很多情況下會覺得那種寫法看著非常別扭,其實只需要掌握了規(guī)則,這些古怪的寫法會大大的提高代碼的性能,我們通過例子來學(xué)習(xí)這些規(guī)則:
復(fù)制代碼 代碼如下:
var x = 3;
var y = x + "2";// => 32
var z = x + 2;// => 5
print(y);
print(z);
通??梢栽贘S代碼中發(fā)現(xiàn)這樣的代碼:
復(fù)制代碼 代碼如下:
if(datamodel.item){
//do something...
}else{
datamodel.item = new Item();
}
//do something...
}else{
datamodel.item = new Item();
}
這種寫法事實上具有更深層次的含義:
應(yīng)該注意到,datamodel.item是一個對象(字符串,數(shù)字等),而if需要一個boolean型的表達式,所以這里進行了類型轉(zhuǎn)換。在JavaScript中,如果上下文需要boolean型的值,則引擎會自動將對象轉(zhuǎn)換為boolean類型。轉(zhuǎn)換規(guī)則為,如果該對象非空,則轉(zhuǎn)換為true,否則為false.因此我們可以采取這種簡寫的形式。
而在傳統(tǒng)的編程語言(強類型)中,我們則需要:
復(fù)制代碼 代碼如下:
if(datamodel.item != null){
//do something...
}else{
datamodel.item = new Item();
}
//do something...
}else{
datamodel.item = new Item();
}
2.1.4類型的判斷
前面講到JavaScript特性的時候,我們說過,JavaScript是一個弱類型的語言,但是有時我們需要知道變量在運行時的類型,比如,一個函數(shù)的參數(shù)預(yù)期為另一個函數(shù):
復(fù)制代碼 代碼如下:
function handleMessage(message, handle){
return handle(message);
}
return handle(message);
}
當調(diào)用handleMessage的函數(shù)傳遞的handle不是一個函數(shù)則JavaScript引擎會報錯,因此我們有必要在調(diào)用之前進行判斷:
復(fù)制代碼 代碼如下:
function handleMessage(message, handle){
if(typeof handle == "function"){
return handle(message);
}else{
throw new Error("the 2nd argument should be a function");
}
}
if(typeof handle == "function"){
return handle(message);
}else{
throw new Error("the 2nd argument should be a function");
}
}
但是,typeof并不總是有效的,比如下面這種情況:
復(fù)制代碼 代碼如下:
var obj = {};
var array = ["one", "two", "three", "four"];
print(typeof obj);//object
print(typeof array); //object
var array = ["one", "two", "three", "four"];
print(typeof obj);//object
print(typeof array); //object
運行結(jié)果顯示,對象obj和數(shù)組array的typeof值均為”object”,這樣我們就無法準確判斷了,這時候,可以通過調(diào)用instanceof來進行進一步的判斷:
print(obj instanceof Array);//false
print(array instanceof Array);//true
第一行代碼返回false,第二行則返回true。因此,我們可以將typeof操作符和instanceof操作符結(jié)合起來進行判斷。
2.2 變量
變量,即通過一個名字將一個值關(guān)聯(lián)起來,以后通過變量就可以引用到該值,比如:
復(fù)制代碼 代碼如下:
var str = "Hello, World";
var num = 2.345;
var num = 2.345;
當我們下一次要引用”Hello, Wrold”這個串進行某項操作時,我們只需要使用變量str即可,同樣,我們可以用10*num來表示10*2.345。變量的作用就是將值“存儲”在這個變量上。
2.2.1基本類型和引用類型
在上一小節(jié),我們介紹了JavaScript中的數(shù)據(jù)類型,其中基本類型如數(shù)字,布爾值,它們在內(nèi)存中都有固定的大小,我們通過變量來直接訪問基本類型的數(shù)據(jù)。而對于引用類型,如對象,數(shù)組和函數(shù),由于它們的大小在原則上是不受任何限制的,故我們通過對其引用的訪問來訪問它們本身,引用本身是一個地址,即指向真實存儲復(fù)雜對象的位置。
基本類型和引用類型的區(qū)別是比較明顯的,我們來看幾個例子:
復(fù)制代碼 代碼如下:
var x = 1;//數(shù)字x,基本類型
var y = x;//數(shù)字y,基本類型
print(x);
print(y);
x = 2;//修改x的值
print(x);//x的值變?yōu)?
print(y);//y的值不會變化
var y = x;//數(shù)字y,基本類型
print(x);
print(y);
x = 2;//修改x的值
print(x);//x的值變?yōu)?
print(y);//y的值不會變化
運行結(jié)果如下:
1
1
2
1
這樣的運行結(jié)果應(yīng)該在你的意料之內(nèi),沒有什么特別之處,我們再來看看引用類型的例子,由于數(shù)組的長度非固定,可以動態(tài)增刪,因此數(shù)組為引用類型:
復(fù)制代碼 代碼如下:
var array = [1,2,3,4,5];
var arrayRef = array;
array.push(6);
print(arrayRef);
var arrayRef = array;
array.push(6);
print(arrayRef);
引用指向的是地址,也就是說,引用不會指向引用本身,而是指向該引用所對應(yīng)的實際對象。因此通過修改array指向的數(shù)組,則arrayRef指向的是同一個對象,因此運行效果如下:
1,2,3,4,5,6
2.2.2變量的作用域
變量被定義的區(qū)域即為其作用域,全局變量具有全局作用域;局部變量,比如聲明在函數(shù)內(nèi)部的變量則具有局部作用域,在函數(shù)的外部是不能直接訪問的。比如:
復(fù)制代碼 代碼如下:
var variable = "out";
function func(){
var variable = "in";
print(variable);//打印”in”
}
func();
print(variable);//打印”out”
function func(){
var variable = "in";
print(variable);//打印”in”
}
func();
print(variable);//打印”out”
應(yīng)該注意的是,在函數(shù)內(nèi)var關(guān)鍵字是必須的,如果使用了變量而沒有寫var關(guān)鍵字,則默認的操作是對全局對象的,比如:
復(fù)制代碼 代碼如下:
var variable = "out";
function func(){
variable = "in";//注意此variable前沒有var關(guān)鍵字
print(variable);
}
func();
print(variable);//全局的變量variable被修改
function func(){
variable = "in";//注意此variable前沒有var關(guān)鍵字
print(variable);
}
func();
print(variable);//全局的變量variable被修改
由于函數(shù)func中使用variable而沒有關(guān)鍵字var,則默認是對全局對象variable屬性做的操作(修改variable的值為in),因此此段代碼會打印:
in
in
2.3運算符
運算符,通常是容易被忽略的一個內(nèi)容,但是一些比較古怪的語法現(xiàn)象仍然可能需要用到運算符的結(jié)合率或者其作用來進行解釋,JavaScript中,運算符是一定需要注意的地方,有很多具有JS編程經(jīng)驗的人仍然免不了被搞得暈頭轉(zhuǎn)向。
我們在這一節(jié)主要講解這樣幾個運算符:
2.3.1中括號運算符([])
[]運算符可用在數(shù)組對象和對象上,從數(shù)組中按下標取值:
復(fù)制代碼 代碼如下:
var array = ["one", "two", "three", "four"];
array[0]
array[0]
而[]同樣可以作用于對象,一般而言,對象中的屬性的值是通過點(.)運算符來取值,如:
復(fù)制代碼 代碼如下:
var object = {
field : "self",
printInfo : function(){
print(this.field);
}
}
object.field;
object.printInfo();
field : "self",
printInfo : function(){
print(this.field);
}
}
object.field;
object.printInfo();
但是考慮到這樣一種情況,我們在遍歷一個對象的時候,對其中的屬性的鍵(key)是一無所知的,我們怎么通過點(.)來訪問呢?這時候我們就可以使用[]運算符:
復(fù)制代碼 代碼如下:
for(var key in object){
print(key + ":" + object[key]);
}
print(key + ":" + object[key]);
}
運行結(jié)果如下:
field:slef
printInfo:function (){
print(this.field);
}
2.3.2點運算符(.)
點運算符的左邊為一個對象(屬性的集合),右邊為屬性名,應(yīng)該注意的是右邊的值除了作為左邊的對象的屬性外,同時還可能是它自己的右邊的值的對象:
復(fù)制代碼 代碼如下:
var object = {
field : "self",
printInfo : function(){
print(this.field);
},
outter:{
inner : "inner text",
printInnerText : function(){
print(this.inner);
}
}
}
object.outter.printInnerText();
field : "self",
printInfo : function(){
print(this.field);
},
outter:{
inner : "inner text",
printInnerText : function(){
print(this.inner);
}
}
}
object.outter.printInnerText();
這個例子中,outter作為object的屬性,同時又是printInnerText()的對象。
2.3.3 == 和 === 以及 != 和 !==
運算符==讀作相等,而運算符===則讀作等同。這兩種運算符操作都是在JavaScript代碼中經(jīng)常見到的,但是意義則不完全相同,簡而言之,相等操作符會對兩邊的操作數(shù)做類型轉(zhuǎn)換,而等同則不會。我們還是通過例子來說明:
print(1 == true);
print(1 === true);
print("" == false);
print("" === false);
print(null == undefined);
print(null === undefined);
運行結(jié)果如下:
復(fù)制代碼 代碼如下:
true
false
true
false
true
false
false
true
false
true
false
相等和等同運算符的規(guī)則分別如下:
相等運算符
如果操作數(shù)具有相同的類型,則判斷其等同性,如果兩個操作數(shù)的值相等,則返回true(相等),否則返回false(不相等).
如果操作數(shù)的類型不同,則按照這樣的情況來判斷:
◆ null和undefined相等
◆ 其中一個是數(shù)字,另一個是字符串,則將字符串轉(zhuǎn)換為數(shù)字,在做比較
◆ 其中一個是true,先轉(zhuǎn)換成1(false則轉(zhuǎn)換為0)在做比較
◆ 如果一個值是對象,另一個是數(shù)字/字符串,則將對象轉(zhuǎn)換為原始值(通過toString()或者valueOf()方法)
◆ 其他情況,則直接返回false
等同運算符
如果操作數(shù)的類型不同,則不進行值的判斷,直接返回false
如果操作數(shù)的類型相同,分下列情況來判斷:
◆ 都是數(shù)字的情況,如果值相同,則兩者等同(有一個例外,就是NaN,NaN與其本身也不相等),否則不等同
◆ 都是字符串的情況,與其他程序設(shè)計語言一樣,如果串的值不等,則不等同,否則等同
◆ 都是布爾值,且值均為true/false,則等同,否則不等同
◆ 如果兩個操作數(shù)引用同一個對象(數(shù)組,函數(shù)),則兩者完全等同,否則不等同
◆ 如果兩個操作數(shù)均為null/undefined,則等同,否則不等同
比如:
復(fù)制代碼 代碼如下:
var obj = {
id : "self",
name : "object"
};
var oa = obj;
var ob = obj;
print(oa == ob);
print(oa === ob);
id : "self",
name : "object"
};
var oa = obj;
var ob = obj;
print(oa == ob);
print(oa === ob);
會返回:
true
true
再來看一個對象的例子:
復(fù)制代碼 代碼如下:
var obj1 = {
id : "self",
name : "object",
toString : function(){
return "object 1";
}
}
var obj2 = "object 1";
print(obj1 == obj2);
print(obj1 === obj2);
id : "self",
name : "object",
toString : function(){
return "object 1";
}
}
var obj2 = "object 1";
print(obj1 == obj2);
print(obj1 === obj2);
返回值為:
true
false
obj1是一個對象,而obj2是一個結(jié)構(gòu)與之完全不同的字符串,而如果用相等操作符來判斷,則兩者是完全相同的,因為obj1重載了頂層對象的toString()方法。
而!=不等和!==不等同,則與==/!==相反。因此,在JavaScript中,使用相等/等同,不等/不等同的時候,一定要注意類型的轉(zhuǎn)換,這里推薦使用等同/不等同來進行判斷,這樣可以避免一些難以調(diào)試的bug。
您可能感興趣的文章:
- JavaScript基本概念初級講解論壇貼的學(xué)習(xí)記錄
- javascript,jquery閉包概念分析
- javascript學(xué)習(xí)筆記(二) js一些基本概念
- JavaScript回調(diào)(callback)函數(shù)概念自我理解及示例
- JavaScript的作用域和塊級作用域概念理解
- JavaScript 基本概念
- javascript中幾個容易混淆的概念總結(jié)
- javascript相關(guān)事件的幾個概念
- 通過實例理解javascript中沒有函數(shù)重載的概念
- 深入理解JavaScript編程中的原型概念
- 深入剖析JavaScript編程中的對象概念
- 帶領(lǐng)大家學(xué)習(xí)javascript基礎(chǔ)篇(一)之基本概念
相關(guān)文章
Javascript Object 對象學(xué)習(xí)筆記
這篇文章主要介紹了Javascript Object 對象學(xué)習(xí)筆記,需要的朋友可以參考下2014-12-12
javascript中call apply 與 bind方法詳解
網(wǎng)上文章雖多,大多復(fù)制粘貼,且晦澀難懂,我希望能夠通過這篇文章,能夠清晰的提升對apply、call、bind的認識,并通過一些具體的示例給大家展示下這3個方法的用法,希望大家能夠喜歡。2016-03-03
Javascript中arguments和arguments.callee的區(qū)別淺析
這篇文章主要介紹了Javascript中arguments和arguments.callee的區(qū)別淺析,本文用一個實例來理解它們的區(qū)別,需要的朋友可以參考下2015-04-04
JavaScript fontcolor方法入門實例(按照指定的顏色來顯示字符串)
這篇文章主要介紹了JavaScript fontcolor方法入門實例,fontcolor方法用于按照指定的顏色來顯示字符串,需要的朋友可以參考下2014-10-10

