一区二区久久-一区二区三区www-一区二区三区久久-一区二区三区久久精品-麻豆国产一区二区在线观看-麻豆国产视频

JavaScript中的類型

一、關(guān)于類型

什么叫做類型?簡單地說,類型就是把內(nèi)存中的一個二進制序列賦予某種意義。比如,二進制序列0100 0000 0111 0000 0001 0101 0100 1011 1100 0110 1010 0111 1110 1111 1001 1110如果看作是64位無符號整數(shù)類型就是4643234631018606494 而按照IEEE 754規(guī)定的浮點數(shù)二進制表示規(guī)則(見附1)雙精度浮點類型則是257.331。

變量類型

大部分計算機語言使用變量來存儲和表示數(shù)據(jù),一些語言會給變量規(guī)定一個類型,在整個程序中(不論是編譯時還是運行時),這個類型都不能被改變。與此相對,JavaScript和一些其它語言的變量可以存儲任何類型,它們使用無類型的變量。變量類型是否存在,是跟語法無關(guān)的,例如C#中也提供了var類型的變量,但是,下面的語句在C#中會出錯:

var a=1;

a=”string”;

原因是C#的var關(guān)鍵字只是省略了變量類型聲明,而根據(jù)初始化表達(dá)式自動推斷變量類型,所以C#的var變量仍然是有類型的。而JavaScript中,任何時刻你都可以把任何值賦值給特定變量,所以JavaScript變量是無類型的。

強類型和弱類型

按照計算機語言的類型系統(tǒng)的設(shè)計方式,可以分為強類型和弱類型兩種。二者之間的區(qū)別,就在于計算時是否可以不同類型之間對使用者透明地隱式轉(zhuǎn)換。從使用者的角度來看,如果一個語言可以隱式轉(zhuǎn)換它的所有類型,那么它的變量、表達(dá)式等在參與運算時,即使類型不正確,也能通過隱式轉(zhuǎn)換來得到正確地類型,這對使用者而言,就好像所有類型都能進行所有運算一樣,所以這樣的語言被稱作弱類型。與此相對,強類型語言的類型之間不一定有隱式轉(zhuǎn)換(比如C++是一門強類型語言,但C++中double和int可以互相轉(zhuǎn)換,但double和任何類型的指針之間都需要強制轉(zhuǎn)換)

為什么要有類型

類型可以幫助程序員編寫正確的程序,它在實際編寫程序的過程中體現(xiàn)為一種約束。一般規(guī)律是,約束越強越不容易出錯,但編寫程序時也越麻煩。變量有類型的強類型語言約束最強,典型代表是C++,變量無類型的弱類型語言約束最弱,典型代表是JavaScript。在JavaScript中,因為約束比較弱,所以容易出現(xiàn)這種錯誤:

var a =200;

var b ="1";

var c= a + b;

你可能期望c是201,但實際上它是"2001",這個錯誤在強類型語言中決不會出現(xiàn)。然而正是因為JavaScript沒有這些約束,所以可以很方便地拼接數(shù)字和字符串類型。所以,約束和靈活性對語言的設(shè)計者而言,永遠(yuǎn)是需要平衡的一組特性。

靜態(tài)類型和動態(tài)類型

類型是一種約束,這種約束是通過類型檢查來發(fā)生作用的。在不同語言中,類型檢查在不同的階段發(fā)生作用,這樣又可以分為編譯時檢查和運行時檢查。對于JavaScript這樣的解釋型語言,也有跟編譯過程比較相似的階段,即詞法分析和語法分析,解釋型語言的類型檢查若在語法分析或者之前的階段完成,也可以認(rèn)為類似于編譯時檢查。所以更合理的說法是靜態(tài)類型檢查和動態(tài)類型檢查。

有趣的是,很多語言雖然編譯時檢查類型,但是它的類型信息仍可以在運行時獲得,如C#中使用元數(shù)據(jù)來保存類型信息,在運行階段,使用者可以通過反射來獲取和使用類型的信息。

JavaScript在設(shè)計的各個方面都以靈活性優(yōu)先,所以它使用動態(tài)類型檢查,并且除了在進行極少數(shù)特定操作時,JavaScript不會主動檢查類型。你可以在運行時獲得任何一個變量或者表達(dá)式的類型信息并且通過程序邏輯檢查它的正確性。

二、JavaScript標(biāo)準(zhǔn)規(guī)定的類型

JavaScript標(biāo)準(zhǔn)中規(guī)定了9種類型:Undefined Null Boolean String Number Object Reference List Completion

其中,Reference List Completion三種類型僅供語言解析運行時使用,無法從程序中直接訪問,這里就暫不做介紹。下面我們可以了解下這六種類型:

Undefined類型

Undefined類型只有一個值undefined,它是變量未被賦值時的值,在JS中全局對象有一個undefined屬性表示undefined,事實上undefined并非JavaScript的關(guān)鍵字,可以給全局的undefined屬性賦值來改變它的值。

Null類型

Null類型也只有一個值null,但是JavaScript為它提供了一個關(guān)鍵字null來表示這個唯一的值。Null類型的語義是“一個空的對象引用”。

Boolean類型

Boolean有兩種取值true和false

String類型

String類型的的正式解釋是一個16位無符號整數(shù)類型的序列,它實際上用來表示以UTF-16編碼的文本信息。

Number類型

JavaScript的Number共有18437736874454810627 (就是 264-253 +3)個值。JavaScript的Number以雙精度浮點類型存儲,除了9007199254740990表示NaN,它遵守IEEE 754(見附1)規(guī)定,占用64位8字節(jié)。

Object類型

JavaScript中最為復(fù)雜的類型就是Object,它是一系列屬性的無序集合,F(xiàn)unction是實現(xiàn)了私有屬性[[call]]的Object,JavaScript的宿主也可以提供一些特別的對象。

三、JavaScript使用者眼中的類型:

前面講了JS標(biāo)準(zhǔn)中規(guī)定的類型,然而一個不能忽略的問題是JS標(biāo)準(zhǔn)是寫給JS實現(xiàn)者看的,對JS使用者而言,類型并不一定要按照標(biāo)準(zhǔn)來定義,比如,因為JS在進行.運算的時候,會自動把非Object類型轉(zhuǎn)換為與其對應(yīng)的對象,所以"str".length其實和(new String("str")).length是等效的,從這個角度而言,認(rèn)為二者屬于同一類型也未嘗不可。我們利用JS中的一些語言特性,可以進行運行時的類型判別,但是這些方法判斷的結(jié)果各不相同,孰好孰壞還需要您自己決定。

typeof——看上去很官方

typeof是JS語言中的一個運算符,從它的字面來看,顯然它是用來獲取類型的,按JavaScript標(biāo)準(zhǔn)的規(guī)定,typeof獲取變量類型名稱的字符串表示,他可能得到的結(jié)果有6種:string、bool、number、undefined、object、function,而且JavaScript標(biāo)準(zhǔn)允許其實現(xiàn)者自定義一些對象的typeof值。

在JS標(biāo)準(zhǔn)中有這樣一個描述列表:

Type

Result

Undefined

"undefined"

Null

"object"

Boolean

"boolean"

Number

"number"

String

"string"

Object (native and doesn't implement [[call]])

"object"

Object (native and implements [[call]])

"function"

Object (host)

Implementation-dependent

下面一個例子來自51js的Rimifon,它展示了IE中typeof的結(jié)果產(chǎn)生"date"和"unknown"的情況:

var xml=document.createElement("xml");
var rs=xml.recordset;
rs.Fields.Append("date", 7, 1);
rs.Fields.Append("bin", 205, 1);
rs.Open();
rs.AddNew();
rs.Fields.Item("date").Value = 0;
rs.Fields.Item("bin").Value = 21704;
rs.Update();
var date = rs.Fields.Item("date").Value;
var bin = rs.Fields.Item("bin").Value;
rs.Close();
alert(date);
alert(bin);
alert([typeof date, typeof bin]);
try{alert(date.getDate())}catch(err){alert(err.message)}

關(guān)于這個最為接近"類型"語義的判斷方式,實際上有不少的批評,其中之一是它無法分辨不同的object,new String("abc")和new Number(123)使用typeof無法區(qū)分,由于JS編程中,往往會大量使用各種對象,而typeof對所有對象都只能給出一個模糊的結(jié)果"object",這使得它的實用性大大降低。

instanceof——原型還是類型?

instanceof的意思翻譯成中文就是"是……的實例",從字面意思理解它是一個基于類面向?qū)ο缶幊痰男g(shù)語,而JS實際上沒有在語言級別對基于類的編程提供支持。JavaScript標(biāo)準(zhǔn)雖然只字未提,但其實一些內(nèi)置對象的設(shè)計和運算符設(shè)置都暗示了一個"官方的"實現(xiàn)類的方式,即從把函數(shù)當(dāng)作類使用,new運算符作用于函數(shù)時,將函數(shù)的prototype屬性設(shè)置為新構(gòu)造對象的原型,并且將函數(shù)本身作為構(gòu)造函數(shù)。

所以從同一個函數(shù)的new運算構(gòu)造出的對象,被認(rèn)為是一個類的實例,這些對象的共同點是:1.有同一個原型 2.經(jīng)過同一個構(gòu)造函數(shù)處理。而instanceof正是配合這種實現(xiàn)類的方式檢查"實例是否屬于一個類"的一種運算符。猜一猜也可以知道,若要檢查一個對象是否經(jīng)過了一個構(gòu)造函數(shù)處理千難萬難,但是檢查它的原型是什么就容易多了,所以instanceof的實現(xiàn)從原型角度理解,就是檢查一個對象的[[prototype]]屬性是否跟特定函數(shù)的prototype一致。注意這里[[prototype]]是私有屬性,在SpiderMonkey(就是Firefox的JS引擎)中它可以用__proto__來訪問。

原型只對于標(biāo)準(zhǔn)所描述的Object類型有意義,所以instanceof對于所有非Object對象都會得到false,而且instanceof只能判斷是否屬于某一類型,無法得到類型,但是instanceof的優(yōu)勢也是顯而易見的,它能夠分辨自定義的"類"構(gòu)造出的對象。

instanceof實際上是可以被欺騙的,它用到的對象私有屬性[[prototype]]固然不能更改,但函數(shù)的prototype是個共有屬性,下面代碼展示了如何欺騙instanceof

function ClassA(){};

function ClassB(){};

var o = new ClassA();//構(gòu)造一個A類的對象

ClassB.prototype = ClassA.prototype; //ClassB.prototype替換掉

alert(o instanceof ClassB)//true 欺騙成功 - -!

Object.prototype.toString——是個好方法?

Object.prototype.toString原本很難被調(diào)用到,所有的JavaScript內(nèi)置類都覆蓋了toString這個方法,而對于非內(nèi)置類構(gòu)造出的對象,Object.prototype.toString又只能得到毫無意義的[object Object]這種結(jié)果。所以相當(dāng)長的一段時間內(nèi),這個函數(shù)的神奇功效都沒有被發(fā)掘出來。

在標(biāo)準(zhǔn)中,Object.prototype.toString的描述只有3句

1. 獲取this對象的[[class]]屬性

2. 通過連接三個字符串"[object ", 結(jié)果(1), 和 "]"算出一個字符串

3. 返回 結(jié)果(2).

顯而易見,Object.prototype.toString其實只是獲取對象的[[class]]屬性而已,不過不知道是不是有意為之,所有JS內(nèi)置函數(shù)對象String Number Array RegExp……在用于new構(gòu)造對象時,全都會設(shè)定[[class]]屬性,這樣[[class]]屬性就可以作為很好的判斷類型的依據(jù)。

因為Object.prototype.toString是取this對象屬性,所以只要用Object.prototype.toString.call或者Object.prototype.toString.apply就可以指定this對象,然后獲取類型了。

Object.prototype.toString盡管巧妙,但是卻無法獲取自定義函數(shù)構(gòu)造出對象的類型,因為自定義函數(shù)不會設(shè)[[class]],而且這個私有屬性是無法在程序中訪問的。Object.prototype.toString最大的優(yōu)點是可以讓1和new Number(1)成為同一類型的對象,大部分時候二者的使用方式是相同的。

然而值得注意的是 new Boolean(false)在參與bool運算時與false結(jié)果剛好相反,如果這個時候把二者視為同一類型,容易導(dǎo)致難以檢查的錯誤。

總結(jié):

為了比較上面三種類型判斷方法,我做了一張表格,大家可以由此對幾種方法有個整體比較。為了方便比較,我把幾種判斷方式得到的結(jié)果統(tǒng)一了寫法:

對象

typeof

instanceof

Object.prototype.toString

標(biāo)準(zhǔn)

"abc"

String

——

String

String

new String("abc")

Object

String

String

Object

function hello(){}

Function

Function

Function

Object

123

Number

——

Number

Number

new Number(123)

Object

Number

Number

Object

new Array(1,2,3)

Object

Array

Array

Object

new MyType()

Object

MyType

Object

Object

null

Object

——

Object

Null

undefined

Undefined

——

Object

Undefined

事實上,很難說上面哪一種方法是更加合理的,即使是標(biāo)準(zhǔn)中的規(guī)定,也只是體現(xiàn)了JS的運行時機制而不是最佳使用實踐。我個人觀點是淡化"類型"這一概念,而更多關(guān)注"我想如何使用這個對象"這種約束,使用typeof配合instanceof來檢查完全可以在需要的地方達(dá)到和強類型語言相同的效果。

附1 IEEE 754 規(guī)定的雙精度浮點數(shù)表示(來自中文wikipedia):

sign bit(符號): 用來表示正負(fù)號

exponent(指數(shù)): 用來表示次方數(shù)

mantissa(尾數(shù)): 用來表示精確度

clip_image001

it知識庫JavaScript中的類型,轉(zhuǎn)載需保留來源!

鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請第一時間聯(lián)系我們修改或刪除,多謝。

主站蜘蛛池模板: 天干天干夜天干天天爽 | 91久久国产精品 | 欧美国产综合在线 | 不卡一区二区三区四区 | 免费国产成高清人在线视频 | 国产成人亚洲精品91专区高清 | 亚洲国产网 | 日韩黄色在线观看 | 亚洲第一色视频 | 免费在线观看色 | 日韩视频在线一区 | 国内小情侣一二三区在线视频 | 婷婷激情综合网 | 一级毛毛片毛片毛片毛片在线看 | 国产成人精品999在线 | 国产精品猎奇系列在线观看 | 国产视频第二页 | 婷婷5月| 黄色美女网站免费看 | 欧美欧美乱码一二三区 | 中文字幕亚洲一区 | 亚洲成综合人影院在院播放 | 91在线免费视频 | 午夜大片免费完整在线看 | 中文字幕一区二区三区在线观看 | 亚洲人成综合在线播放 | 中文字幕在线观看一区二区三区 | 亚洲图片欧美在线 | 四虎影视永久在线精品免费 | 久久精品国产99国产精品 | 精品伊人久久大线蕉地址 | 亚洲国产精品人久久 | 欧美成人综合在线 | 国产偷2018在线观看午夜 | a毛片全部播放免费视频完整18 | 看大片全色黄大色黄 | 色91视频 | www.色在线 | 精品美女视频在线观看2023 | 网色网站 | 国产日韩欧美综合色视频在线 |