DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> JavaScript入門知識 >> 關於JavaScript >> JavaScript基礎篇(3)之Object、Function等引用類型
JavaScript基礎篇(3)之Object、Function等引用類型
編輯:關於JavaScript     

閱讀目錄

Object類型

1、通過構造函數來創建
2、通過字面量表示法來創建對象

Array類型

同樣Array也有兩種創建方式:
如果我們想要打印數組中所有的值,直接打印數組的變量名就可以:
往數組添值:
棧方法、隊列方法:
 關於數組的排序:
 數組的一些操作方法:
查找位置方法
迭代方法

歸並方法

Date類型

RegExp類型

Function類型

三種表示法:

方法重載
函數內部屬性(arguments 和 this)

基本包裝類型

浏覽器的內置對象
URI 編碼方法

總結

我們在《一步步學習javascript基礎篇(1):基本概念》中簡單的介紹了五種基本數據類型Undefined、Null、Boolean、Number和String。今天我們主要介紹下復雜數據類型(即引用數據類型)

Object類型

我們用的最多的引用類型就屬object類型了,一般用來存儲和傳輸數據是再好不過的。然,它的兩種創建方式我們是否了解呢?

1、通過構造函數來創建

如: var obj = new Object();

在js中的引用類型有個非常靈活的用法,可以動態的附加屬性和賦值。

如:

var obj = new Object();
obj.name = "張三";//動態添加屬性並賦值
obj.age = 23;
alert(obj.name);

2、通過字面量表示法來創建對象

現在大家用得比較多的就是字面量表示法來創建對象了。

如:

var obj = {
 name: "張三",
 age: 23
};
alert(obj.age);

和上面的效果是等效的。通過這樣方式創建感覺結構更加的清晰,更加有封裝的感覺。:)

我們還可以這樣用

如:

var obj = {};
obj.name = "張三";
obj.age = 23;
alert(obj.age);

如:

var obj = {
 "name": "張三",//給屬性加上雙引號
 age: 23
};
alert(obj.name);

是不是感覺很強大很靈活呢?我在訪問屬性的時候一般都是點出來,但是還有另外的方式。

如:(我們可以使用中括號的形式來訪問屬性值)

var obj = {
 "name tow": "張三",
 age: 23
};
//alert(obj.name tow);//這裡會報錯,屬性不能有空格
alert(obj["name tow"]);//這裡可以正常彈出

例:

Array類型

除了object之外,應該屬數組用的最多了。下面來羅列下常見用法。

同樣Array也有兩種創建方式:

var arr = new Array(1, 2, 3, 4, 5);//通過構造函數創建
var arr2 = [5, 4, 3, 2, 1];//通過字面量表達式來創建 

上面兩種方式是等效的,我們可以直接通過下標的方式來訪問數組: alert(arr[2]); 。

如果我們想要打印數組中所有的值,直接打印數組的變量名就可以:

var arr2 = [5, 4, 3, 2, 1];//通過字面量表達式來創建
var str2 = "";
for (var i = 0; i < arr2.length; i++) {
 str2 += arr2[i] + ","
}
alert(str2);//打印拼接的字符串  
alert(arr2);//直接打印變量名(實際上會自動調用數組的toString方法)

例:

 var arr2 = [5, 4, 3, 2, 1];//通過字面量表達式來創建
var str2 = "";
for (var i = 0; i < arr2.length; i++) {
 str2 += arr2[i] + ","
}
alert(str2);//打印拼接的字符串

例:

 var arr2 = [5, 4, 3, 2, 1];//通過字面量表達式來創建
alert(arr2);//直接打印變量名(實際上會自動調用數組的toString方法)

上面直接打印arr2,我們發現默認都是以逗號分隔的。那麼有時候,我們不想用逗號怎麼辦呢。那你可能可以用到join方法

 var arr2 = [5, 4, 3, 2, 1];//通過字面量表達式來創建
alert(arr2.join('_'));//直接打印變量名(實際上會自動調用數組的toString方法)

往數組添值:

我們可以直接: arr2[4] = 7; arr2[5] = 8; 

還有一種更加巧妙地添值方式: arr2[arr2.length] = 9; arr2[arr2.length] = 10; ,下標length剛好是數組最大長度的下一個,添加值後length再次動態自動累計。

棧方法、隊列方法:

什麼是棧?(後進先出)。什麼是隊列?(先進先出),我們怎樣用數組來模仿這種數據結構的訪問方式?下面通過一張圖來解釋下數組對象提供的四個方法。

從圖可以看出:shift和push、unshift和pop的組合可以實現棧的數據結構訪問,shitf和pop、shift和unshift的組合可以實現隊列的數據機構訪問方式。 這裡需要注意:pop和shift取數據的同時,數組中對於的值也同時移除了。

例:

 var arr2 = [5, 4, 3, 2, 1];
alert("arr2.pop:" + arr2.pop() + " arr2:" + arr2);

 關於數組的排序:

關於數組的排序有sort(正)reverse(反)。

先看個例子,大家猜想下結果:

var arr2 = [5, 14, 23, 12, 1];
alert(arr2.sort());

 然結果並不是我們想要的:

 var arr2 = [5, 14, 23, 12, 1];
alert(arr2.sort());

 為什麼會這樣呢?因為sort不會直接比較數字類型,而已轉為string了再做的比較。那麼我們想要比較數字怎辦?我們可以往sort傳函數,例:

 function mycompare(o1, o2)
{
 return o1 - o2;//如果為正數則o1大,負數則o2大,零則相等。
}
var arr2 = [5, 14, 23, 12, 1];
alert(arr2.sort(mycompare));

 有人會問o1和o2是怎麼來的?這是sort函數規定的。這樣說大家可能不好接受。下面,我們自己來模擬下sort的排序,大家就明白了。

var arr2 = [5, 14, 23, 12, 1, 123, 23, 4, 5, 6, 32, 5, 3, 2, 1];
arr2.mysort = function (fun) {
 //*********************具體排序過程*******************
 for (var i = 0; i < arr2.length - 1; i++) {
  for (var j = 0; j < arr2.length - i; j++) {
   if (fun(arr2[j], arr2[j + 1]) > 0) {//這裡用我們傳進來的方法判斷是否要排序調換位置
    var temp = arr2[j];
    arr2[j] = arr2[j + 1];
    arr2[j + 1] = temp;
   }
  }
 }
 //***************************************************
 return arr2;
} 
function mycompare(o1, o2) {
 return o1 - o2;//回調函數(具體的比較規則)
}
alert(arr2.mysort(mycompare));

 var arr2 = [5, 14, 23, 12, 1, 123, 23, 4, 5, 6, 32, 5, 3, 2, 1];
arr2.mysort = function (fun) {
 //*********************具體排序過程*******************
 for (var i = 0; i < arr2.length - 1; i++) {
  for (var j = 0; j < arr2.length - i; j++) {
  if (fun(arr2[j], arr2[j + 1]) > 0) {//這裡用我們傳進來的方法判斷是否要排序調換位置
   var temp = arr2[j];
   arr2[j] = arr2[j + 1];
   arr2[j + 1] = temp;
   }
  }
 }
 //***************************************************
 return arr2;
}
function mycompare(o1, o2) {
 return o1 - o2;//回調函數(具體的比較規則)
}
alert(arr2.mysort(mycompare));

當然,我們模擬的並不是那麼的好,大概就是這麼個意思。

反序就簡單了:(直接reverse()就可以了)

function mysort(o1, o2)
{
 return o1 - o2;//如果為正數則o1大,負數則o2大,零則相等。
}
var arr2 = [5, 14, 23, 12, 1];
arr2.sort(mysort);
arr2.reverse();
alert(arr2);

數組的一些操作方法:
concat創建一個新的副本,並合並傳進來的參數

var colors = ["red", "green", "blue"];
var colors2 = colors.concat("yellow", ["black", "brown"]);
alert(colors); //red,green,blue
alert(colors2); //red,green,blue,yellow,black,brow

slice創建一個新的副本,取數組的位置數據

var colors = ["red", "green", "blue", "yellow", "purple"];
var colors2 = colors.slice(1);//從下標為1的開始,到末尾
var colors3 = colors.slice(1, 4);//從下標1(包含1)到4(不包含4)
alert(colors2); //green,blue,yellow,purple
alert(colors3); //green,blue,yellow

splice會改變原數組數據,可實現對數組的刪、插和替換

 var colors = ["red", "green", "blue"];
 var removed = colors.splice(0, 1); // 刪除第一項(從下標0開始,刪除1項)
 alert(colors); // green,blue
 alert(removed); // red,返回的數組中只包含一項
 removed = colors.splice(1, 0, "yellow", "orange"); // 從位置 1 開始插入兩項(從下標0開始,刪除0項,並插入後面的參數數據)
 alert(colors); // green,yellow,orange,blue
 alert(removed); // 返回的是一個空數組
 removed = colors.splice(1, 1, "red", "purple"); // 插入兩項,刪除一項(從下標1開始,刪除1項[也就是yellow],並插入後面的參數數據)
 alert(colors); // green,red,purple,orange,blue
 alert(removed); // yellow,返回的數組中只包含一項

查找位置方法

indexOf()和 lastIndexOf(),就是查找在數組中的位置,和string中的對應方法差不多。

迭代方法

 every():對數組中的每一項運行給定函數,如果該函數對每一項都返回 true,則返回 true。
 filter():對數組中的每一項運行給定函數,返回該函數會返回 true 的項組成的數組。
 forEach():對數組中的每一項運行給定函數。這個方法沒有返回值。
 map():對數組中的每一項運行給定函數,返回每次函數調用的結果組成的數組。
 some():對數組中的每一項運行給定函數,如果該函數對任一項返回 true,則返回 true。

以上方法都不會修改數組中的包含的值。

如:

var numbers = [1,2,3,4,5,4,3,2,1];
var everyResult = numbers.every(function(item, index, array){
return (item > 2);
});
alert(everyResult); //false

其中。forEach和map區別不大,只是一個有返回值,一個沒有。實際中我們用forEach比較多,下面我們模擬forEach的實現。

var str = "", str2 = "";
var numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1];
numbers.forEach(function (item, index, array) {
 str += item + "_";
});
//**************其實我們完全可以自己模擬實現*******
numbers.myforEach = function (fun) {
 for (var i = 0; i < numbers.length; i++) {
  fun(numbers[i], i, numbers);
 }
}
numbers.myforEach(function (item, index, array) {
 str2 += item + "*";
})
//***************************************************
alert("str:" + str + " str2:" + str2);

var str = "", str2 = "";
var numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1];
numbers.forEach(function (item, index, array) {
 str += item + "_";
});
//**************其實我們完全可以自己模擬實現*******
numbers.myforEach = function (fun) {
 for (var i = 0; i < numbers.length; i++) {
  fun(numbers[i], i, numbers);
 }
}
numbers.myforEach(function (item, index, array) {
 str2 += item + "*";
})
//***************************************************
alert("str:" + str + " str2:" + str2);

歸並方法

 reduce()和 reduceRight(),這兩個方法是比較有意思的,以前還真沒接觸過。先看例子,再解釋:

var values = [1,2,3,4,5];
var sum = values.reduce(function(prev, cur, index, array){
 return prev + cur;
});
alert(sum); //15

也是個循環,第一次執行 prev 是 1, cur 是 2。第二次, prev 是 3(1 加 2 的結果), cur 是 3(數組的第三項)。這個過程會持續到把數組中的每一項都訪問一遍,最後返回結果。reduceRight只是方向相反。

下面我們來模擬:

var numbers = [1, 2, 3, 4, 5, 3];
var sum = numbers.reduce(function (prev, cur, index, array) {
 return prev + cur;
});
//***********************模擬實現reduce**************************
numbers.myreduce = function (fun) {
 for (var i = 0; i < numbers.length; i++) {
  var temp = 0;
  for (var j = 0; j < i; j++)
   temp += numbers[j];
  var tempNum = fun(temp, numbers[i], i, numbers);
 }
 return tempNum;
}
//*************************************************
var sum2 = numbers.myreduce(function (prev, cur, index, array) {
 return prev + cur;
})
alert("sum:" + sum + " sum2:" + sum2); //

var numbers = [1, 2, 3, 4, 5, 3];
var sum = numbers.reduce(function (prev, cur, index, array) {
 return prev + cur;
});
//***********************模擬實現reduce**************************
numbers.myreduce = function (fun) {
for (var i = 0; i < numbers.length; i++) {
 var temp = 0;
 for (var j = 0; j < i; j++)
  temp += numbers[j];
   var tempNum = fun(temp, numbers[i], i, numbers);
  }
  return tempNum;
}
//*************************************************
var sum2 = numbers.myreduce(function (prev, cur, index, array) {
 return prev + cur;
})
alert("sum:" + sum + " sum2:" + sum2); //

Date類型

我們很多時候需要測試一個函數的性能,可以取它的執行進過時間:

//取得開始時間
var start = Date.now();
//調用函數
doSomething();
//取得停止時間
var stop = Date.now(),
result = stop – start;

下面列出一些常用方法

getTime() 返回表示日期的毫秒數;與valueOf()方法返回的值相同
setTime(毫秒) 以毫秒數設置日期,會改變整個日期
getFullYear() 取得4位數的年份(如2007而非僅07)
getUTCFullYear() 返回UTC日期的4位數年份
setFullYear(年) 設置日期的年份。傳入的年份值必須是4位數字(如2007而非僅07)
setUTCFullYear(年) 設置UTC日期的年份。傳入的年份值必須是4位數字(如2007而非僅07)
getMonth() 返回日期中的月份,其中0表示一月, 11表示十二月
getUTCMonth() 返回UTC日期中的月份,其中0表示一月, 11表示十二月
setMonth(月) 設置日期的月份。傳入的月份值必須大於0,超過11則增加年份
setUTCMonth(月) 設置UTC日期的月份。傳入的月份值必須大於0,超過11則增加年份
getDate() 返回日期月份中的天數(1到31)
getUTCDate() 返回UTC日期月份中的天數(1到31)
setDate(日) 設置日期月份中的天數。如果傳入的值超過了該月中應有的天數,則增加月份
setUTCDate(日) 設置UTC日期月份中的天數。如果傳入的值超過了該月中應有的天數,則增加月份
getDay() 返回日期中星期的星期幾(其中0表示星期日, 6表示星期六)
getUTCDay() 返回UTC日期中星期的星期幾(其中0表示星期日, 6表示星期六)
getHours() 返回日期中的小時數(0到23)
getUTCHours() 返回UTC日期中的小時數(0到23)
setHours(時) 設置日期中的小時數。傳入的值超過了23則增加月份中的天數
setUTCHours(時) 設置UTC日期中的小時數。傳入的值超過了23則增加月份中的天數
getMinutes() 返回日期中的分鐘數(0到59)
getUTCMinutes() 返回UTC日期中的分鐘數(0到59)
setMinutes(分) 設置日期中的分鐘數。傳入的值超過59則增加小時數
setUTCMinutes(分) 設置UTC日期中的分鐘數。傳入的值超過59則增加小時數
getSeconds() 返回日期中的秒數(0到59)
getUTCSeconds() 返回UTC日期中的秒數(0到59)
setSeconds(秒) 設置日期中的秒數。傳入的值超過了59會增加分鐘數
setUTCSeconds(秒) 設置UTC日期中的秒數。傳入的值超過了59會增加分鐘數
getMilliseconds() 返回日期中的毫秒數
getUTCMilliseconds() 返回UTC日期中的毫秒數
setMilliseconds(毫秒) 設置日期中的毫秒數
setUTCMilliseconds(毫秒) 設置UTC日期中的毫秒數
getTimezoneOffset() 返回本地時間與UTC時間相差的分鐘數。例如,美國東部標准時間返回300。在某地進入夏令時的情況下,這個值會有所變化

RegExp類型

兩種表示法:

var pattern1 = /at/g; 
var re = new RegExp("cat", "g"); 

後面的參數代表模式,如:g:表示全局(global)模式、i:表示不區分大小寫(case-insensitive)模式、m:表示多行(multiline)模式

關於正則了解不是很清楚,後期有機會在單獨學習整理正則這塊。

Function類型

三種表示法:

function sum (num, num) { return num + num; } 
var sum = function(num, num){ return num + num; }; 
var sum = new Function("num", "num", "return num + num"); 

以上三種都是可行的,不過我們平時用得比較多的是第一種,第二種也有用,第三種用得比較少,但是最能看出function的本質,其實就是一個Function對象的實例。

我們來看看1和2的區別。

alert(sum1(1, 2));//彈出值 3
alert(sum2(1, 2));//報異常[sum2 is not a function]
function sum1(num1, num2) { return num1 + num2; }
var sum2 = function (num1, num2) { return num1 + num2; };

因為js解析器是從上到下的解析,在執行sum2的時候還沒有定義,所以報異常。但是sum1比較特殊,是申明式的。在執行sum1之前就會”預解析“(函數聲明提升)。相當於把sun1的定義提到了最上面(放到源代碼樹的頂部)。

方法重載

嚴格來說,js中是沒有方法重載的,不過我們可以根據參數的個數來模擬。(還有,js中函數的形參我們是不確定類型的)

例:
上面並沒有出現我們預料中的結果,因為第二次定義的sun1不是實現的重載,而是直接覆蓋了第一次的定義。下面,我們就簡單的模擬實現方法重載:

function sum1(num1, num2, num3) {
 if (num1 != undefined && num2 != undefined && num3 != undefined) {
  return num1 + num2 + num3;
 }
 else if (num1 != undefined && num2 != undefined)
  return num1 + num2;
}
alert(sum1(1, 2));
alert(sum1(1, 2, 3));

 函數內部屬性(arguments 和 this)

arguments:類數組對象,包含著傳入函數中的所有參數。下面通過arguments實現上面的模擬重載:

function sum(num, num, num) {
 var temp = ;
 if (arguments.length == ) {
  //***********具體實現其邏輯*********************
  for (var i = ; i < arguments.length; i++) {
   temp += arguments[i];
  }
 }
 else {
  //***********具體實現其邏輯*********************
  for (var i = ; i < arguments.length; i++) {
   temp += arguments[i];
  }
 }
 return temp;
}
alert("+=" + sum(, ) + " ++=" + sum(, , ));

 function sum1(num1, num2, num3) {
var temp = 0;
if (arguments.length == 3) {
//***********具體實現其邏輯*********************
for (var i = 0; i < arguments.length; i++) {
temp += arguments[i];
}
}
else {
//***********具體實現其邏輯*********************
for (var i = 0; i < arguments.length; i++) {
temp += arguments[i];
}
}
return temp;
}
alert("1+2=" + sum1(1, 2) + " 1+2+3=" + sum1(1, 2, 3));

我們在第一篇博文裡面有提一個問題:

六、

 var fun = function (num1) {
  if (num1 <= 1) {
   return 1;
  }
  else {
   return num1 * fun(num1 - 1);
  }
 }
 var fun2 = fun;
 fun = function () {
  return 1;
 }
 alert(fun2(5));//這裡彈出什麼? 

 不過,並沒有同學去解答,有人可能覺得太簡單,或是不樂意懶得去解答。這題的答案是:

 為什麼會是這個答案呢?好像和我們預料中的不一樣。下面我們圖解:

我們可能發現了一個問題,那就是第4步調用的已經不是所在的這個函數本身了(也就是沒有遞歸了),這不是我們想要的。我們要的是,不管外面怎麼改變,4處都代表所在的函數指針。那麼我們可以用到arguments的callee方法,例:

 函數的另一個內部屬性this:

 首先我們看看這樣一個問題:

var color = "red";
var o = { color: "blue" };
function sayColor() {
 alert(this.color);
}
sayColor(); //"red"
o.sayColor = sayColor;
o.sayColor(); //"blue"

為什麼會有不同的結果?我們記住一句話,一般情況"哪個對象點出來的方法,this就是哪個對象"。上面的例子其實等效於:

window.color = "red";
var o = { color: "blue" };
function sayColor() {
 alert(this.color);
}
window.sayColor(); //"red"
o.sayColor = sayColor;
o.sayColor(); //"blue" 

 雖然"哪個對象點出來的方法,this就是哪個對象",但是有時候我們不想要這樣的結果,我們不想用對象點或者對象點出了想this是另外的對象。那麼我們可以使用call:

 傳如的第一個參數,直接賦值給函數裡面的this。和call類似的有apply,區別看下面:

 var o = { color: "blue" };
 var o2 = { color: "red" };
 function sayColor(a, b) {
  alert(this.color + a + b);
 }
 sayColor.apply(o, [1, 2]);//只傳兩個參數,第一個是為this賦值的對象,第二個是函數實參數組
 sayColor.call(o2, 1, 2);//可以傳多個參數,第一個是為this賦值的對象,後面的是函數實參用逗號分割

基本包裝類型

 在這個系列的第一篇中有個問題:

四、

var obj1 = {}; obj1.name2 = "張三";
var str1 = "test"; str1.name2 = "李四";
alert(obj1.name2 + " " + str1.name2);

 為什麼會是這樣的結果?因為str1.name2設置值的時候訪問的是string的包裝類,然後再次訪問str1.name2之前就把之前那個包裝類已經被銷毀。

為什麼要有包裝類?

因為可以像操作引用對象一樣操作基本數據類型,如: var s1 = "some text"; var s2 = s1.substring(2);

哪些基本類型有包裝類?

Boolean、Number和String類型。

浏覽器的內置對象

Global(其實也就是我們平時用的window)和Math(一些計算功能)

URI 編碼方法

encodeURI、encodeURIComponent、decodeURI、decodeURIComponent
//encodeURI主要對完整的url進行編碼(空格會編碼成%20)【對應該的解碼decodeURI】
alert(window.encodeURI("http://i.cnblogs.com/EditPosts.aspx?postid = 5002381"));
//encodeURIComponent會把url中的所有特殊字符進行轉碼(所以,我們一般用來進行部分url轉碼,如Url中的參數)【對應的解碼decodeURIComponent】
alert(window.encodeURIComponent("http://i.cnblogs.com/EditPosts.aspx?postid = 5002381"));
eval

這是一個js中最最最強大的函數了,相對與一個獨立的解析器。如我文中的操作實例就是用這個函數實現的。

如:

 <textarea class="test_code" style="width: %;height:px; max-height: px;">
//。。。。這裡面寫js代碼
var obj = {}; obj.name = "張三";
var str = "test"; str.name = "李四";
alert(obj.name + " " + str.name);
 </textarea>
 <input type="button" class="test_code_but" onclick="eval($(this).prev().val());" value="運行" />

效果圖:

當然,你還的引入jqeruy問題,博客園中默認就已經引入了。所以,你不需要再次引入,你測試的話是看不到alert彈框的,因為博客園禁掉了。我的是用的jquery ui中的Dialog對話框做的。

XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved