一、介紹 沒錯,這是第五篇,到了引用類型,這次要分成兩次博文了,太多內容了,這是前篇,篇幅很長也很多代碼,主要講引用類型和常用的引用類型,代碼試驗過的,老鐵沒毛病。 堅持看堅持寫,不容易不容易,希望大家能在這博客中學到東西。能和大家分享,不錯不錯。而且啊,我想通過自己的認識,思考來得到一些個人見解, ...
一、介紹
- 沒錯,這是第五篇,到了引用類型,這次要分成兩次博文了,太多內容了,這是前篇,篇幅很長也很多代碼,主要講引用類型和常用的引用類型,代碼試驗過的,老鐵沒毛病。
- 堅持看堅持寫,不容易不容易,希望大家能在這博客中學到東西。能和大家分享,不錯不錯。而且啊,我想通過自己的認識,思考來得到一些個人見解,以便能大家能容易理解,書中那枯燥的文字。如果大家在看後有種感覺說這家伙寫得不錯,那我就滿足了。嘿嘿嘿
不廢話了,進入正題...
二、引用類型
引用類型?如果有學過java一類的語言的,可以把它看成類,書中又說這種描述不准確。。。什麼也別說了,我們把引用類型理解為對象定義。
有時發現語言這種東西,真的神奇,說引用類型你可能不理解,我說對象定義,就可能理解了。
引用類型(對象定義):描述了一類對象所具有的屬性和方法。
聽我娓娓道來:
1.引用類型(對象定義): 人類就是引用類型,它描述了人類對象所共有的屬性和方法。人的屬性比如,有眼睛,有頭,手等;人的方法(可以說是行為):走路,吃飯等等。每個引用類型只有一種定義,即它是集體性的指向。
2.引用類型的值:就是每一個new出來的對象(引用類型的實例),對象有很多,就像我們億萬人民一樣。同一個引用類型的對象們有共同的屬性和方法,但我們可以動態添改屬性,就像每個人都有不同的地方。
3.js中內置的引用類型:object類型,Array類型,Function類型,Date類型,RegExp類型等等,當然我們也可以自定義引用類型。
看了圖的創建對象,我們看看代碼中創建對象:
//這裡創建了一個對象叫obj,它是object類型的,那麼它就有object類型共有的屬性和方法
var obj = new Object();
//這裡創建了一個對象叫arr,它是Array類型的,那麼它就有Array類型共有的屬性和方法
var arr = new Array();
//我們可以創建很多對象
var arr1 = new Array();
var arr2 = new Array();
通俗的講:如果我說人類,在你的大腦中就有個大概的人的模型,對,我說數組,你大腦就有個數組的大概樣子,但是你不知道它具體的樣子。具體的東西是對象才能展現出來的,比如我說小明(如果你認識小明),那你就知道小明是個怎樣的人了。
到這裡應該把引用類型理解得差不多了,下麵就說js中的內置的引用類型吧。
三、Js內置的引用類型
為什麼需要介紹js的內置引用類型,主要是我們用得多。我們就像從小去認識一種事物一樣,比如魚類,一開始我們不知道這東西,後來媽媽老是跟我們說這是魚啊寶貝,告訴你魚是怎樣怎樣的,然後對這種類型有了基本認識。
在js的世界里我們沒世上那麼多的東西,內置的引用類型我們就先理解Object,Array,Date,RegExp,Function這幾個常用的。
1.Object類型
Object 類型是使用得最多得類型,雖然Object得實例不具備多少功能,但對於應用程式存儲和傳輸數據而言,是好的選擇。
1.1創建Object對象:
先出生了再說,創建Obeject的對象的2種方法:
1.直接new。
語法:new操作符跟Obeject構造函數
//new操作符後面加Obejct的構造函數
var o = new Obeject();
//添加屬性
o.name = "yuan";
2.對象字面量
語法:花括弧,裡面的屬性用鍵值對形式,每個屬性用逗號隔開,最後一個屬性不用逗號。
//對象字面量(有種封裝數據的感覺)
var p = {
data:13,
name:'yuan',
age:11
}
//兩者對比
var x = {}; //創建一個空對象和new Object() 相同
1.2訪問屬性
1.通過點表示法
var p = new Object();
p.name = '淵源遠願';
console.log(p.name); //淵源遠願
2.通過方括弧法
var o = new Object();
o.age = 22;
console.log(o["age"]); //22
//方括弧可以用變數來訪問屬性
var otherAge = "age";
console.log(o[otherAge]); //22
通常來說都是用點方法比較多的。
1.3 Object的屬性和方法:
不贅述了:看看同系列的第三篇吧
2.Array類型
2.1 創建數組
兩種方式:
1.new Array();
//創建一個空數組
var arr1 = new Array();
//創建一個長度為10的空數組,
var arr2 = new Array(10);
//創建一個包含一個字元串good的數組
var arr3 = new Array("good");
特別說明:當傳進去括弧中的只有一個值,這個值是數值的話,就會創建長度為這個數值的數組;如果是其他值,那就是包含一個這個值的數組。
2.數組字面量,使用方括弧:
// 創建空的
var fish = [];
//創建有值的,在括弧里添加
var cars = ["BMW","BenZ","Ferrari"];
//註意,創建數組不要留空項。瀏覽器相容性問題,IE8或以前版本會認為這是有3項,下麵這種不建議。
var nums = [1,2,];
2.2 訪問數組中的值
和其他語言一樣下標訪問(下標從0開始):
//創建數組
var cars = ["BMW","BenZ","Ferrari"];
console.log(cars[0]); //BMW
console.log(cars[2]); //Ferrari
//修改數組某個值,對其重新賦值就像
cars[0] = "lala";
2.3 常用屬性和方法
這裡給出常用的屬性和方法,更詳細的在js的文檔裡面有。
1.length屬性:返回數組的長度。
var num = [1,2,3,4,5]
console.log(arr.length); //5
//妙用:通過改變數組的length可以改變數組長度
arr.length = 10; //現在num 數組長度為10了
console.log(num); //[1,2,3,4,5,,,,,] 後面5個值是空的
2.Array.isArray()方法:判斷對象是不是數組
//用了判斷改對象是不是數組
var arr = [];
console.log(Array.isArray(arr)); //true
console.log(Array.isArray("s"); //false
3.join()方法:改變數組分隔方式,返回新的分隔符字元串
//原來是使用逗號連接的
var arr = [1,2,3,4,5];
//用|連接,註意只是返回字元串,不會改變數組裡面的連接方式
console.log((arr.join("|")); //'1|2|3|4|5'
console.log(arr); //[1,2,3,4,5] 還是一樣用逗號的
4.棧方法:pop()和push()組合使用實現棧的先進後出
//引入這兩方法是為了用數組實現棧的功能
//push() :從數組最後添加數據
var stack = new Array();
//添加一個10
stack.push(10);
//添加一個5
stack.push(5);
//添加一個100
stack.push(100);
//現在stack中有3個數值
console.log(stack); //[10,5,100]
//pop() :從數組最後刪除並返回該數據
stack.pop(); //100 100被刪除
console.log(stack); //[10,5] 剩下兩數
5.隊列方法:shift()和push()組合使用實現先進先出
這裡就不再舉例了,類似與棧的操作,只是操作的函數不同,棧的pop是從後面刪除,而隊列的shift是從前面刪除,這樣就先進先出了。
6.重排序方法:sort()和reverse()
//sort()預設是按照ascii碼表排序的,所以會出現下麵這種情況
var arr = [5,12,18,1];
console.log(arr.sort()); //[1,12,18,5]
//為了可以對數字正常排序,為sort傳入一個比較函數
function comp(a,b){
return a-b;
}
//再來排序
arr.sort(comp);
console.log(arr); //[1,5,12,18] 這次正確了
//reverse()是將數組完全顛倒
arr.reverse();
console.log(arr); //[18,12,5,1]
7.合併和剪切:concat() , slice()
//1.concat() 在該數組的基礎上添加元素,返回一個新數組(不會改變原數組)
var arr1 = [1,2,3];
//在arr1基礎添加4,5,6,並返回給arr2,不會改變arr
var arr2 = arr1.concat(4,5,6);
console.log(arr2); //[1,2,3,4,5,6]
//2.slice() 通過傳入開始和終點值來剪切數組,並返回新數組
var arr3 = arr2.slice(1,5);
console.log(arr3); //[2,3,4,5]
8.最強大的數組方法:splice()
刪除:接受兩個參數,第一個是開始刪除位置,第二個是刪除的個數,返回一個刪除項的數組
//用來刪除
var arr = [1,2,3,4,5,6,7];
var del_arr = arr.splice(0,4); //從0位開始刪除4項,即前4項
console.log(del_arr); //[1,2,3,4]
console.log(arr); //[5,6,7] arr數組剩下後面3項了
插入:輸入3個參數,起始位置,0(刪除項數設為0),要插入的值
//用來插入
var arr1 = [1,2,3,4,5,6];
arr1.splice(3,0,100);//從位置3插入一個100值
console.log(arr1); //[1,2,3,100,4,5,6];
替換:指定3個參數,起始位置,要刪除的項,插入的值
//替換
var arr2 = [1,2,3,4,5];
//我要替換3,替換成100
arr2.splice(2,1,100); //起始位是2,刪除1項(就是3了),載插入100,ok
console.log(arr2); //[1,2,100,4,5]
9.位置函數:indexOf()和lastIndexOf():這兩個方法用來找數值下標位置。都接受兩個參數,第一個是要找的值,第二個是開始位置
//indexOf() 只傳一個參數時預設從0開始找數值,找到返回這個數的數組位置,沒有返回-1
var arr = [100,12,123,1234];
console.log(arr.indexOf(123)); //2 數組的位置2
//lastIndexOf() 和indexOf查找順序正好相反,它從數組末尾開始找起
console.log(arr.lastIndexOf(100)); //0
10.forEach()方法,對每一項進行處理
//接受一個函數,函數傳入2個參數表示當前數值和其下標位置
var arr = [1,2,3,4,5];
arr.forEach(function(item, index){
console.log(item + 1);
}
//輸出 2,3,4,5,6 每一項都加1了
3.Date類型
3.1 創建對象
//創建一個時間對象,保存著當前時間
var n = new Date();
3.2 常用方法
var now = new Date();
//getDate() 返回當前天數,一個月的某天(0-31)
console.log(now.getDate()); //20
//getMonth() //返回月份
console.log(now.getMonth()); //9,這裡的9表示10月 (0-11)
//getFullYear(),返回當前年份
console.log(now.getFullYear()); //2017
更多方法在js文檔中。
4.RegExg類型
ES通過RegExg類型來支持正則表達式,語法:var e = /pattern/flag
其中pattern表示正則表達式,flag表示標識,標識可以一個或多個。
flags有3個,這些flags可以組合使用
flags | 說明 |
---|---|
g | 全局模式,該模式應用於所有的字元串 |
i | 不區分大小寫模式,確定匹配項時忽略模式與字元串的大小寫 |
m | 多行模式,一行文本到尾後還會查下一行的字元串,如果有的話 |
4.1 創建RegExg對象
1.字面量方式
//懶啊,直接書上的例子
var p1 = /at/g; //匹配所有"at" 的實例
var p2 = /[bc]at/i //匹配第一個bat或cat,不區分大小寫
var p3 = /.at/gi //匹配所有at結尾的組合,不區分大小寫
//正則中如果想在字元中包含元字元需要對其進行轉義
//這裡和p3不同的是對.這個元字元進行轉義,用\符號轉義
var p4 = /\.at/gi; //這裡的意思是匹配所有的".at",不區分大小寫。
2.使用new RegExg構造函數
//RegExg() 接受兩個參數,一個是正則表達式,一個是標誌
var pattern1 = new RegExg("at","gi");
//pattern1和pattern2完全等價
var pattern2 = /at/gi;
4.2 RegExp的實例屬性
有5個實例屬性:global,ignoreCase,multiline,lastIndex,source
//直接上例子,瞭解作用是什麼就好了
//有一個正則對象
var p = /hello/i;
//global屬性,返回布爾值,表示是否設置了g標誌
console.log(p.global); //false
//ignoreCase屬性,返回布爾值,表示是否設置了i標誌
console.log(p.ignoreCase); //true
//multiline屬性,返回布爾值,表示是否設置了m標誌
console.log(p.multiline); //false
//lastIndex屬性,返回整數,表示開始搜索下一個匹配字元的位置,從0開始
console.log(p.lastIndex); //0
//source屬性,返回正則表達式的字元串形式
console.log(p.source); //"hello"
4.3 RegExp常用方法
1.exec()方法:接受一個參數,這參數是應用模式的字元串,然後返回包含第一個匹配項的數組
var p = /p/;
var str = "happy";
var arr = p.exec(str);
console.log(arr); // ["p",index:2,input:"happy"] 返回這個數組,第一個值表示匹配到的字元,index表示字元所在的位置,input表示應用的字元串
2. test() 方法:用於知道這個字元串與模式是否匹配,接受一個字元串參數,返回布爾值
var p1 = /ry/g;
console.log(p1.test("ryuan")); //true,字元串中有ry這字元串,所以返回true
5.Function類型
核心:函數即對象
5.1 定義函數
定義函數有下麵3種方法,常用的是1,2種
//1.函數聲明
function getName(){
var name = 'ry-yuan';
return name;
}
//2.函數表達式
var getAge = function(){
var age = 100;
return age;
}
//3.使用Function構造函數,前面1-n個是參數,最後一個參數的是函數體,這種不推薦使用。
var sum = new Function("num","return num");
5.2 函數聲明和函數表達式的區別
上面的定義函數常用1,2中,分別是函數聲明和函數表達式,那他們有什麼區別?
如果聽過聲明提升的話就很容易理解下麵的內容,js解析器執行時會先找到所有的聲明,將其提升到頂部。有什麼用?看例子:
//函數聲明,我們先運行sayHello,但是不會報錯,因為函數聲明已經在解析時被提到頂部
sayHello(); //hello everyone
function sayHello(){
console.log("hello everyone");
}
//函數表達式,用var定義函數名.用函數表達式,不會提升,所以先運行sayBye就會找不到函數體
sayBey(); //報錯 TypeError: sayBye is not a function
var sayBye = function(){
console.log("bye bye");
}
5.3 函數名是指向函數的指針
一個函數在js種就是一個Function的實例,函數名就是對實例的引用,一個指針,前面的對象中也有說過。那麼一個函數就可以有多個函數名了。
//定義一個函數,函數名是sum
var sum = funtion(num1,num2){
return num1+num2;
}
//講sum複製給otherSum,那麼otherSum和sum都指向同一個function對象
otherSum = sum;
otherSum(100,420); //520
sum(1300+14); //1314
//對sum設置為null,sum變數就不在指向function對象
sum = null;
//otherSum依然能夠使用
otherSum(1,9); //10
5.4 函數沒有重載
上面說了,函數名只是函數的指針,函數名是變數一樣,重覆複製就會覆蓋原來的。
在java語言來說,有不同的參數數量也稱為重載,但是js中沒這種操作
//函數聲明,fn為函數名
function fn(num1, num2){
return num1+ num2;
}
//再來函數聲明,fn為函數名
function fn(num){
return num;
}
//fn只會指向最後一次聲明的函數
fn(1,43); //1
5.5 函數像值一樣傳遞
因為函數名本來就是一個變數,所以函數也可以像值一樣被傳遞。說實話,函數能被當做值來傳遞確實是一件好玩的事,大家有興趣可以去瞭解回調函數,這裡先不介紹了。
//聲明一個函數fn1,它可以接受兩個參數,一個是函數,一個是值
function fn1(fn,value){
return (fn(value));
}
//聲明一個fn2,接受一個參數
function fn2(val){
console.log(val+1000);
}
//fn2當成參數傳遞給fn1
fn1(fn2,24); //1024
5.6 函數內部對象
函數內部有兩個特殊的對象arguments和this
1.arguments:包含傳入函數的所有參數,主要用於保存函數參數,它可以看做是一個數組
function fn(num1,num2){
console.log(arguments);
}
fn(100,200); //{'0':100,'1':200}
//arguments有一個callee的屬性,它是一個指針,用來指向當前這個函數
//例如一個遞歸調用,階乘函數,裡面的arguments.callee就是等價於這個函數
function factorial(num){
if(num<=1){
return 1;
}
else{
return num*arguments.callee(num-1);
}
}
2.this:指向調用這個函數的對象
//全局作用域下
var hi = 'hi';
//一個普通object對象
var obj = { hi = "obj hi"};
function say(){
console.log(this.hi)
}
//say函數在全局作用域下定義,直接執行,this將指向window對象,所以hi是windows對象的。
say(); //hi
//將say賦予obj對象,並且obj來調用say,這次this將指向obj對象
obj.say = say;
obj.say(); //obj hi
5.7函數屬性和方法
1.length屬性:函數接受參數的個數
function fn(n,m){};
alert(fn.length); //2
2.prototype屬性:後面博客再說,厲害嘞
3.apply()和call()方法:擴充函數依賴的運行環境。就像是把一個函數給一個個的對象使用。
var color = "red";
var obj = {color: "green"};
//先聲明一個函數
function fn(){
console.log(this.color);
}
//給window對象用
fn.call(window); //red
//給obj對象用
fn.call(obj); //green
apply和call功能是一樣的:不同就是接受參數不同,大家第一個參數都是作用域對象,後面的apply接收一個參數數組,call則是接收一個個參數。
//聲明一個函數add
function add(num1,num2){
return num1+num2;
}
//在另一個函數調用,第一個是this,後面參數一個個輸入
//這裡用call
function otherAdd(n1,n2){
return add.call(this,n1,n2);
}
//這裡用apply,第一都是this,後面接受參數變成數組形式
function otherAdd(n1,n2){
return add.apply(this,[n1,n2]);
}
四、說說
這篇東西挺長篇幅,適合慢慢看,也適合作為溫故js的引用類型的知識,多看幾遍。可以可以,如果覺得寫得好,就點贊啊,還會繼續更新哦。
同系列前幾篇:
第一篇:JavaScript--我發現,原來你是這樣的JS(一)(初識)
第二篇:JavaScript--我發現,原來你是這樣的JS(二)(基礎概念--軀殼篇)
第三篇:JavaScript--我發現,原來你是這樣的JS(三)(基礎概念--靈魂篇)
第四篇:JavaScript--我發現,原來你是這樣的JS(四)(看看變數,作用域,垃圾回收是啥)
本文出自博客園:http://www.cnblogs.com/Ry-yuan/
作者:Ry
歡迎轉載,轉載請標明出處