JavaScript的原生引用型別

尛沫發表於2014-06-12

引用型別是一種資料結構,用於將資料和功能組織在一起,也常稱做類。ECMAScript從技術上說是一門物件導向的語言,但它不具備傳統的面嚮物件語言所支援的類和介面等基本結構。

Object型別

大多數引用型別的值都是Object型別的例項,建立object例項的方式有兩種,第一種是使用new操作符,例如:

var myobj = new Object();

另一種方式是使用物件字面量表示法,例如:

var myobj  = {
  name : "obj",
  weight : 20
};

如果留空其花括號,則可以定義只包含預設屬性和方法的物件,例如:

var myobj = {};

一般來說,訪問物件屬性時使用的都是點表示法,也可以使用方括號一膚淺法來訪問物件的屬性,例如:

var myobj = {
  name = "obj"
}
alert(myobj["name"]);

Array型別

ECMAScript陣列的每一項可以儲存任何型別的資料,而且,陣列的大小是可以動態調整的,即隨著資料的新增自動增長以容納新增資料。建立陣列有兩種形式,第一種是使用Array建構函式,例如:

var myarray = new Array();

也可以給Array建構函式傳遞陣列要儲存的專案數量,例如:

var myarray = new Array(20);

也可以向Array建構函式傳遞陣列中應該包含的項,例如:

var myarray = new Array("a", "b", "c");

使用Array建構函式時也可以省略new操作符,第二種建立陣列的方式是使用陣列字面量表示法,例如:

var myarray = ["a", "b", "c"];

在讀取陣列的值時,要使用方括號並提供相應值的基於0的數字索引,例如:

alert(myarray[0]);

陣列的項數儲存在其length屬性中,例如:

alert(myarray.length);

這個屬性不是隻讀的,可以通過設定這個屬性,從陣列的末尾移除項或向陣列中新增新項。

Array方法

所有物件都具有toLocaleString()、toString()和valueOf()方法,其中,呼叫陣列的toString()和valueOf()方法會返回相同的值,即由陣列中每個值的字串形式拼接而成的一個以逗號分隔的字串。實際上,它會呼叫陣列每一項的toString()方法,而toLocaleString()方法則是呼叫陣列每一項的toLocaleString()方法。

ECMAScript陣列也提供了讓陣列行為類似於其他資料結構的方法:push()和pop()。push()方法可以接收任意數量的引數,把它們逐個新增到陣列末尾,並返回修改後陣列的長度,而pop()方法則從陣列末尾移除最後一項,然後返回移除的項,例如:

myarray.push("d");
myarray.pop();

此外,ECMAScript陣列還提供了類似佇列行為的方法:shift()和unshift()。shift()能夠移除陣列中的第一個項並返回該項,而unshift()相反,它能在陣列前端新增任意個項並返回陣列的長度,例如:

myarray.shift();
myarray.unshift("A", "B");

陣列中已經存在兩個可以直接用來重排序的方法:reverse()和sort()。reverse()方法會反轉陣列項的順序,而sort()方法按升序排列陣列項,例如:

myarray.reverse();
myarray.sort();

最後,ECMAScript為操作已經包含在陣列中的項提供了很多方法。其中,concat()方法也可基於當前陣列中的所有項建立一個新陣列,在沒有傳遞引數的情況下,它只是複製當前陣列並返回副本,如果傳遞給concat()方法的是一或多個陣列,則該方法會將這些陣列中的每一項都新增到結果陣列中,如果傳遞的值不是陣列,這些值就會被簡單地新增到結果陣列的末尾。

slice()方法能夠基於當前陣列中的一或多個項建立一個新陣列,它可以接受一或兩個引數,即要返回項的起始和結束位置,只有一個引數的情況下,slice()方法返回從該引數指定位置開始到當前陣列末尾的所有項。

splice()方法的主要用途是向陣列的中部插入項,它有很多種用法,如果提供兩個引數(要刪除的第一項的位置和要刪除的項數),則會刪除陣列中的項,如果提供三個引數(起始位置,要刪除項數,要插入的項),則可以實現在陣列中插入元素。

Date型別

Date型別使用自UTC1970年1月1日午夜開始經過的毫秒數來儲存日期,在使用這種儲存格式的條件下,Date型別儲存的日期能夠精確到1970年1月1日之前或之後的285616年。

建立一個日期物件,使用new操作符和Date建構函式即可,例如:

var now = new Date();

在不傳遞引數的情況下,新建立的物件自動獲得當前日期和時間,如果想根據特定的日期和時間建立日期物件,必須傳入表示該日期的毫秒數。為了簡化這一過程,ECMAScript提供了兩個方法:Date.parse()和Date.UTC()。

Date.parse()方法接收一個表示日期的字串引數,嘗試根據這個字串返回相應日期的毫秒數,如果傳入Date.parse()方法的字串不能表示日期,那麼它會返回NaN,例如:

var mydate = new Date(Date.parse("May 01, 2000"));

Date.UTC()方法同樣也返回表示日期的毫秒數,但它與Date.parse()在構建值時使用不同的資訊。Date.UTC()的引數分別是年份、基於0的月份(一月是0)、月中的哪一天(1到31)、小時數(0到23)、分鐘、秒以及毫秒數,只有前兩個引數是必須的,如果省略其他引數,則一律設為0,例如:

var mydate = new Date(Date.UTC(2000, 1, 1, 8, 10, 10));

Date方法

Date型別也重寫了toLocaleString()、toString()和valueOf()方法,但這些方法返回的值與其他型別中的方法不同。toLocaleString()方法會按照與瀏覽器設定的地區相適應的格式返回日期和時間。而toString()方法則通常返回帶有時區資訊的日期和時間。valueOf()方法根本不返回字串,而是返回日期的毫秒錶示。

RegExp型別

ECMAScript通過RegExp型別來支援正規表示式,語法如下:

var expression = /pattern/ flags;

其中模式(pattern)部分是正規表示式,每個正規表示式都可帶有一或多個標誌(flag)。正規表示式的匹配模式支援以下3個標誌:

  • g: 表示全域性模式,即模式將被用於所有字串,而非在發現第一個匹配項時停止。
  • i: 表示不區分大小寫模式。
  • m: 表示多行模式,即在到達一行文字末尾時還會繼續查詢下一行。

RegExp方法

RegExp物件的主要方法是exec(),它接受一個引數,即要應用模式的應符串,然後返回包含第一個匹配項資訊的陣列,沒有匹配項的情況下返回null。返回的陣列是Array()的例項,但包含兩個額外屬性index和input,index表示匹配項在字串中的位置,input表示應用正規表示式的字串,例如:

var input = "this is a test";
var pattern = /test/gi;
var matches = pattern.exec(text);
alert(matches.index);
alert(matches.input);
alert(matches[0]);

對於exec()方法,即使設定了模式g,每次也只返回一個匹配項,但每次呼叫都會在字串中繼續查詢新匹配項。

另一個方法是test(),它接受一個字串引數,在模式與引數匹配的情況下返回true,否則返回false,例如:

var input = "this is a test";
var pattern = /test/gi;
alert(pattern.test());

RegExp繼承的toLocaleString()和toString()方法都會返回正規表示式的字面量。

RegExp屬性

RegExp建構函式包含一些屬性,這些屬性可以通過兩種方式訪問它們,一個長屬性名,一個短屬性名(Opera不支援短屬性名)。

RegExp建構函式屬性

長屬性名 短屬性名說明
Input$_最近一次要匹配的字串(Opera不支援)
lastMath $& 最近一次的匹配項(Opera不支援)
lastParen $+ 最近一次匹配的捕獲組(Opera不支援)
lastContext $` input字串中lastMatch之前的文字
multiline $* 是否所有表示式都使用多行模式(IE和Opera不支援)
rightContext $' input字串中lastMatch之後的文字

Function型別

函式實際上是物件,每個函式都是Function物件的例項,而且都與其他引用型別一樣具有屬性和方法。函式名實際上也是一個指向函式的指標,不會與某個函式繫結。函式通常使用函式宣告語法定義,例如:

function myfunc(myvar) {
  return myvar;
}

也可以使用如下方式 :

var myfunc = function(myvar) {return myvar;};

第二種方式是使用Function建構函式,它可以接收任意數量的引數,但最後一個引數始終都被看成是函式體,例如:

var myfunc = new Function("myvar", "return myvar;");

但是不推薦使用這種方式,因為這種語法會導致解析兩次程式碼,從而影響效能,但這種語法有助於理解函式是物件的概念。

如果宣告兩個同名函式,結果就是後面的函式覆蓋了前面的函式,因為函式名相當於指標。

解析器在執行環境中載入資料時,會率先讀取函式宣告,並使其在執行任何程式碼前可用,但函式表示式則必須等到解析器執行到它所在的程式碼行,才會被真正解析執行,例如:

alert(myfunc1(1)); //正確
function myfunc1(myvar) {
  return myvar;
}
alert(myfunc2(1)); //錯誤
var myfunc2 = function(myvar) {
  return myvar;
}

因為ECMAScript中函式名本身就是變數,所以函式也可以作為值來使用,比如可以將一個函式作為另一個函式的結果返回,例如:

function myfunc() {
  return function() {
    return 1;
  }
}

Function方法

每個函式都包含兩個非繼承而來的方法:apply()和call()。這兩個方法的用途都是在特定的作用域中呼叫函式。

apply()方法接受兩個引數,一個是在其中執行函式的作用域,另一個是引數陣列,第二個引數可以是Array的例項,也可以是arguments物件,例如:

function myfunc1() {
}
function myfunc2() {
  return myfunc1.apply(this, arguments);
}

call()方法與apply()方法的作用相同,只是在於接收引數的方式不同,對於call()方法而言,第一個引數是作用域,其餘引數都是直接傳遞給函式的,例如:

function myfunc1() {
}
function myfunc2(myvar) {
  return myfunc1.call(this, myvar);
}

Function屬性

ECMAScript中的函式是物件,所有也有屬性和方法,每個函式都包含兩個屬性:length和prototype。其中length屬性表示函式希望接收的命名引數的個數。

對於ECMAScript中的引用型別而言,prototype是儲存它們所有例項方法的真正所在,例如toString()和valueOf()等方法實際都儲存在prototype名下,只不是通過各自物件的例項訪問,在建立自定義引用型別及實現繼承時,prototype屬性極為重要。

在函式內部,有兩個特殊的物件:arguments和this.arguments包含傳入函式中的所有引數,這個物件還有一個callee屬性,該屬性是一個指標,指向擁有這個agruments物件的函式。this與Java和C#中的this大致類似,引用的是函式據以執行操作的物件,或者說this是函式在執行時所處的作用域。

本文為Anyforweb技術分享部落格,需要了解網站建設及更多Web應用相關資訊,請訪問anyforweb.com。

相關文章