題記
從[我的博客]中搬運過來的,主要的目的是用于自己學(xué)習(xí)和整理思路,以及用到時查詢的作用转质。在hexo的博客主題中酪碘,實現(xiàn)了目錄導(dǎo)航定位的效果。不知道簡書上怎么樣么夫?
目錄
-
第三章
- 3.1 語法
- 3.4 數(shù)據(jù)類型
- 3.5 操作符
- 3.6 語句
- 3.7 函數(shù)
-
[第五章 引用類型](#第五章 引用類型)
- 5.2 [數(shù)組類型](#5.2 數(shù)組類型)
- 5.3 [Date類型](#5.3 Date類型)
-
- 6.1 [理解對象](#6.1 理解對象)
- 6.2 [創(chuàng)建對象](#6.2 創(chuàng)建對象)
第二章 javascript簡介
- netscape創(chuàng)建LiveScript腳本語言者冤。搭java順風(fēng)車就改為javascript。
- js三部分:ECMAScript档痪,dom涉枫,bom
- script標簽的defer和async屬性只針對外部文件,一般不用腐螟,沒有這兩者的時候愿汰,就會按照在頁面中出現(xiàn)的位置先后執(zhí)行的困后。
- js文件放在html外部的優(yōu)勢:可維護性,可緩存衬廷,適應(yīng)未來摇予。
- 如果瀏覽器不支持javascript,那么可以用noscript標簽來寫出替代說明文字吗跋。
第三章 基本概念
3.1 語法
- 區(qū)分大小寫
- 標識符
- 注釋
單行(//) 多行(/* */) - 嚴格模式 use strict
javascript的一種不同的解析與執(zhí)行模型侧戴。一些不確定的行為將得到處理以及某些不安全的操作會拋出錯誤。 - 語句
3.2 關(guān)鍵字和保留字
全部關(guān)鍵字:
break跌宛,case酗宋,catct,continue疆拘,debugger蜕猫,default,delete入问,do丹锹,else,finally芬失,for楣黍,function,if棱烂,in租漂,instanceof,new颊糜,return哩治,switch,this衬鱼,throw业筏,try,typeof鸟赫,var蒜胖,void,while抛蚤,with
3.4 數(shù)據(jù)類型
- 五個基本的數(shù)據(jù)類型:
string,number,boolean,null,undefined - 一個復(fù)雜類型:
object
3.4.1 typeof操作符
var huang = "hzhaung";
var zhuang=null;
console.log(typeof(huang)); //string
console.log(typeof(95)); //number
console.log(typeof(1 == 2)); //booleam
console.log(typeof(a)); //undefined
console.log(typeof(zhuang)); //object 原因:null是被認為是一個空的對象指針
3.4.2 Undefined類型
未申明的變量以及為初始化的變量都是undefined台谢。
3.4.3 null類型
null值表示一個空的對象指針。
null == undefined 返回true
注意的是一般設(shè)置變量為null是為了用這個變量來保存對象岁经,故而要寫出var xx=null朋沮。
3.4.4 boolean類型
- false,""缀壤,0+NAN樊拓,null纠亚,undefined都是false。換句話說就是其他的都是true了骑脱。
- 區(qū)別大小寫菜枷。
3.4.5 number類型
var num1 = 070; //八進制
var num2 = 0xA; //十六進制
var num3 = 10; //十進制
- NUMBER.MIN_VALUE或者NUMBER.MAX_VALUE超出就會自動轉(zhuǎn)換成infinity,如果是負的就在前面加上-叁丧。
ifFinity( ):判斷數(shù)值是否在有限數(shù)值范圍內(nèi)啤誊,true表示在,false表示不在拥娄。
NaN(not a number)
- 任意涉及NaN的操作都會返回NaN;
- NaN與任何值都不相等蚊锹,包含NaN本身。
isNaN( ):接受參數(shù)后會將其轉(zhuǎn)化成數(shù)值稚瘾,不能轉(zhuǎn)化的話就會返回true牡昆。
console.log(isNaN("huang")); //true
console.log(isNaN(true)); //false
console.log(isNaN(NaN)); //true
數(shù)值轉(zhuǎn)換:
函數(shù) | 作用對象 |
---|---|
Number( ) | 可用于任何數(shù)據(jù)類型 |
parseInt( ) | 針對字符串 |
parseFloat( ) | 針對字符串 |
Number的轉(zhuǎn)換規(guī)則:
參數(shù) | 結(jié)果 |
---|---|
boolean | false-0;true-1 |
number | 簡單的傳入換個返回 |
null | 0 |
undefined | NaN |
string | “123”-123;“1.1”-1.1摊欠;“0xf”-15丢烘;“”-0;其他-NaN) |
object | 調(diào)用valueOf( ),然后依照前面的規(guī)則 |
NaN | 調(diào)用toString( ),然后依照前面的規(guī)則 |
parseInt( )示例:
console.log(parseInt("1234blue")); //1234
console.log(parseInt("0xA")); //0
console.log(parseInt("22.5")); //22
var num1 = parseInt("10",2); //2
var num2 = parseInt("10",8); //8
var num2 = parseInt("10",10); //10
var num2 = parseInt("10",16); //16
3.4.6 String類型
- toString( )除null和undefined,因為他們沒有這個方法些椒。一般是不用參數(shù)的播瞳,可以加一個參數(shù)來表示數(shù)值的基數(shù)。
- String( )規(guī)則:null返回"null",undefined返回“undefined”免糕。(在不知道要轉(zhuǎn)化的值是不是null或者undefined)
3.4.7 Object類型
一組數(shù)據(jù)和功能的集合赢乓。每個實例具有以下的屬性和方法。對象是實例的基礎(chǔ)石窑。
屬性 | 作用 |
---|---|
Constructor | 保存用于創(chuàng)建當(dāng)前對象的函數(shù)牌芋,構(gòu)造函數(shù) |
hasOwnproperty(propertyName) | 檢查給定的屬性在當(dāng)前的實例中是否存在。不是在實例的原型中松逊。 |
isPrototypeof(object) | 檢查對象是否是另一個對象的原型躺屁。 |
propertyIsEnumerable | 檢查是否可以用for-in來枚舉。 |
toLocaleString( ) | 返回對象的字符串表示经宏。 |
toString( ) | 返回對象的字符串表示楼咳。 |
valueOf( ) | 返回對象的字符串,數(shù)值或布爾值表示烛恤,通常和上個方法的返回值相同。 |
3.5 操作符
在對對象使用操作符的時候余耽,要調(diào)用valueOf( )或toString( )來獲得可以操作的值缚柏。
3.5.1 一元操作符
一元操作符:++,--碟贾,+币喧,-轨域。前置和后置的區(qū)別:前置的時候語句也改變。
遞增和遞減操作符的規(guī)則如下:
var str = "1";
var str1 = "z";
var b = false;
var f = 1.1;
var o = {
valueOf: function(){
return -1;
}
};
console.log(++str); //2
console.log(++str1);//NaN
console.log(++b); //1
console.log(++f);//2.1
console.log(++o);//0
//如果是對象杀餐,則會先調(diào)用valueOf(),然后根據(jù)返回的值來確定加減之后的值干发。
3.5.2 位操作符
32位,最后一個位表示符號位史翘,0位正1為負枉长。 正數(shù)就是常見的,對于負數(shù)則是以補碼的形式儲存(絕對值琼讽,反碼必峰,加1)。
但是輸出負數(shù)時候這些操作都是隱藏的钻蹬,輸出的時候就是常見負數(shù)在前面加符號的形式吼蚁。
var num = -18;
console.log(num.toString(2));//"-10010"
對于非數(shù)值使用位操作符,則先自動調(diào)用Number( )问欠,然后再應(yīng)用位操作肝匆。
- 按位非( ~)
返回數(shù)值的反碼:操作數(shù)的負數(shù)減1。
var num = 29;
var num1 = ~ num;
console.log(num1); //-26
- 按位與
- 按位或
- 按位異或
- 左移(<<)
移出的空位就以0補充顺献。 - 右移
3.5.3 布爾操作符
1.邏輯非
對象-false旗国;空-true;非空-false滚澜;0-true粗仓;任意非0-false;null-true设捐;NaN-true借浊;undefined-true
2.邏輯與
var result = true && false;
3.邏輯或
3.5.4 乘性操作符
乘法,除法和求模
如果有一個不是數(shù)值萝招,則會先自動調(diào)用number()之后再返回結(jié)果蚂斤。
......
3.5.5 加性操作符
加法特殊:
- 兩個字符串:就拼接起來。
- 只有一個字符串槐沼,則將另一個轉(zhuǎn)換成字符串曙蒸,然后拼接。
- 有一個是對象岗钩,數(shù)值或者布爾值纽窟,則調(diào)用toString( ),然后再拼接。
- 對于undefined和null,則調(diào)用String( )取到"undefined"和"null"兼吓。
console.log(5+"5"); //"55"
減法特殊:
不是數(shù)值的調(diào)用Number( )就OK啦臂港。
3.5.6 關(guān)系操作符
規(guī)則:如示例代碼
console.log(5 > 4);//true
console.log("h" > "z") //false 轉(zhuǎn)換為字符編碼比較。
console.log(5<"2") //false "2"自動轉(zhuǎn)化成2
3.5.7 相等操作符
數(shù)據(jù)類型 | 說明 |
---|---|
一個boolean | 先轉(zhuǎn)化成數(shù)值然后再判斷 |
string+number | string轉(zhuǎn)化成數(shù)值先 |
對象+非對象 | 調(diào)用對象的valueOf( )方法,得到的值再比較 |
null+undefined | 相等 |
有NaN | false |
對象+對象 | 比較是不是同一個人對象 |
全等和不全等:
- ===:未經(jīng)轉(zhuǎn)化的情況下相等才會返回true
null == undefined -----true
null === undefined -----false
3.5.8 條件操作符
variable = boolean_expression ? true_value : false_value ;
3.5.9 賦值操作符
3.5.10 逗號操作符
var num1,num2,num3;
3.6 語句
整理不常用的审孽,if县袱,for就整理啦。
3.6.2 do-while語句
只有在循環(huán)體重的代碼執(zhí)行之后佑力,才會測試出口條件式散。即,循環(huán)體內(nèi)的代碼至少會執(zhí)行一次打颤。
var i = 0;
do{
i += 2;
}while(i < 10);
3.6.5 for-in 語句
一種準確的迭代語句暴拄,可以用來枚舉對象的屬性。
3.6.6 label語句
標簽 labe:statement瘸洛。這個標簽可以通過break或者continue來引用揍移,一般與for語句配合使用。
3.6.7 break和continue語句
- break會立即退出循環(huán)
- continue也會立即退出循環(huán)反肋,但是退出后會從循環(huán)的頂部繼續(xù)執(zhí)行那伐。
var no = 0;
for(var i= 1;i<10;i++){
if(i % 5 == 0){
continue;
}
no++ ;
}
console.log(no);//8
var no = 0;
for(var i= 1;i<10;i++){
if(i % 5 == 0){
break;
}
no++ ;
}
console.log(no);//4
結(jié)合label可以說明是退出的那個循環(huán)。
var num = 0;
outermost:
for(var i=0;i<10;i++){
for(var j=0;j<10;j++){
if(i == 5 && j==5){
break outermost;
}
}
}
3.6.8 with語句
將代碼的作用域設(shè)置到一個特定的對象中石蔗。
with(location){
var gs = search.substring(1); //等價于var gs = location.search.substring(1);
var hostName = hostname;
var url = href;
}
3.7 函數(shù)
好處:封裝罕邀,任意時刻調(diào)用。
ECMAScript中函數(shù)可以通過return語句返回值养距。執(zhí)行return后就會停止诉探。如果return語句不帶返回的值,則會默認返回undefined棍厌。
注:eval和arguments不可以定義為變量肾胯。
函數(shù)的參數(shù):
- 函數(shù)內(nèi)部的參數(shù)是一個數(shù)組,arguments對象耘纱。 類似array敬肚,arguments[0]是合法的,而且也有l(wèi)ength屬性束析。故: 在定義函數(shù)的時候參數(shù)是非必須的艳馒,在調(diào)用的時候加上參數(shù)也不會出問題。這是區(qū)別其他語言的员寇。
- arguments對象可以和命名的參數(shù)一起使用弄慰。但是兩者的內(nèi)存空間是不一樣的。
3.7.2 沒有重載
沒有重載:由于js函數(shù)的特點蝶锋,則是無法實現(xiàn)重載的陆爽,如果存在兩個則后取。
第五章 引用類型
5.2 Array類型
js的數(shù)組可以保存任何類型的數(shù)據(jù)扳缕,也可以自動增長墓陈。
// 創(chuàng)建方法一:Array構(gòu)造函數(shù)
var colors = new Array();
//創(chuàng)建長度是20
var colors = new Array(20);
// 創(chuàng)建方法二:數(shù)組字面兩表示法恶守。
var colors = ["red", "yellow", "white"];
數(shù)組不僅僅是可讀的。如下:
var colors = ["red", "blue", "green"];
colors.length = 2;
alert(colors[2]); //undefined 第三項移除了
5.2.1檢測數(shù)組
if(value instanceof Array){
xxx;
}
但是這種方法是有問題:
- 假定單一的全局執(zhí)行環(huán)境贡必,如果有多個框架,則就會有多個全局執(zhí)行環(huán)境庸毫。從而存在多個不同版本的構(gòu)造函數(shù)仔拟。
改進:isArray( )
if(Array.isArray(value)){
xxx;
}
5.2.1轉(zhuǎn)換方法
轉(zhuǎn)換方法 | 說明 |
---|---|
toLocaleString( ) | 類似toString( ) |
toString( ) | 會返回由數(shù)組中每個值得字符串形式憑借而成的一個以逗號分隔的字符串。 |
valueOf( ) | 返回的還是數(shù)值 |
eg:
var colors=["red","blcak","white"]
console.log(colors.valueOf());//["red", "blcak", "white"]
console.log(colors.toString());//red,blcak,white
join( ):方法講數(shù)組按照()內(nèi)的參數(shù)連接起來飒赃。
var colors=["red","blcak","white"]
var test_one = colors.valueOf().join();
var test_two = colors.valueOf().join("-");
console.log(test_one);//red,blcak,white
console.log(test_two);//red-blcak-white
5.2.3棧方法
數(shù)組可以表現(xiàn)的像棧一樣利花,棧是一種可以限制插入和刪除項的數(shù)據(jù)結(jié)構(gòu)。后進先出载佳。
方法 | 功能 |
---|---|
push( ) | 將參數(shù)里面的對象逐個添加到數(shù)組中炒事,并返回數(shù)組修改后的長度值。 |
pop( ) | 與push的作用相反,但是返回值是數(shù)組的最后一項 |
var colors=["red","blcak","white"]
console.log(colors.push("huang" , "zhuang"))//5;
5.2.4 隊列方法
隊列的訪問規(guī)則是“先進先出”蔫慧,表現(xiàn)在隊列的末端添加項挠乳,在隊列的前端移除項。
方法 | 功能 |
---|---|
shift( ) | 移除數(shù)組中的第一項姑躲,并返回該項 |
unshift( ) | 與shift的作用相反,可以在數(shù)組的前端添加任意個項并返回數(shù)組的長度睡扬。 |
//模擬隊列的組合
push( ) + shift( )
unshift( ) + pop( )
5.2.5 重排序方法
方法 | 功能 |
---|---|
reverse( ) | 反轉(zhuǎn)數(shù)組項的排序 |
sort( ) | 按照升序的方法排列數(shù)組項,會調(diào)用每個項的toString( )轉(zhuǎn)型方法黍析,比較的是字符串 |
var values = [0, 1, 5, 10, 15];
values.sort( );
console.log(values);//[0, 1, 10, 15, 5]因為是比較的字符串卖怜,所以5在最后。
可見以上的sort( )的方法不夠完美阐枣。
sort( )可以接受一個比較函數(shù)作為參數(shù)來完善不足马靠。
function compare(value1, value2) {
return value1 - value2;
}
values.sort(compare);
console.log(values);//[0, 1, 5, 10, 15]
可見,完美解決蔼两,達到排序的效果甩鳄。
5.2.6 操作方法
方法 | 功能 |
---|---|
concat( ) | 基于當(dāng)前數(shù)組中的所有項創(chuàng)建一個新的數(shù)組(副本),然后將接受到的參數(shù)添加到這個副本的末尾宪哩。 |
slice( ) | 基于當(dāng)前的數(shù)組中的一個或者多個創(chuàng)建一個新的數(shù)組 |
splice( ) | 向數(shù)組的中部插入項娩贷。 |
// concat
var colors = ["red", "green", "yellow"];
var color_new = colors.concat("huang",["zhuang","hz"]);
console.log(color_new);//["red", "green", "yellow", "huang", "zhuang", "hz"]
// slice
// 接受一個或者兩個參數(shù)指定位置開始和到當(dāng)前數(shù)組末尾的所有項。不會影響原始數(shù)組锁孟。
var colors = ["red","green","blue","yellow","purple"];
var colors2 = colors.slice(1);
console.log(colors2);//["green", "blue", "yellow", "purple"]
var colors3 = colors.slice(1,4);
console.log(colors3);//["green", "blue", "yellow"]
splice( )詳解:
1.刪除
可以刪除任意數(shù)量的項彬祖,指定兩個參數(shù):要刪除的第一項的位置和要刪除的項數(shù)。會返回刪除的項品抽。返回的是一個數(shù)組储笑。
var colors = ["red","green","blue","yellow","purple"];
var remove = colors.splice(0, 2);
console.log(colors);//["blue", "yellow", "purple"]
console.log(remove);//"red", "green"]
2.插入
可以添加任意數(shù)量的項,提供3個參數(shù)圆恤,起始位置突倍,0和要插入的項。
var removed = colors.splice(1,0,"huang","zhuang");
console.log(colors);//["blue", "huang", "zhuang", "yellow", "purple"]
console.log(removed);//[ ]
3.替換
可以在指定的地方出入任意數(shù)量的項,同事刪除任意數(shù)量的項羽历。
var removed = colors.splice(1,1,"huang","zhuang");
console.log(colors);//["blue", "huang", "zhuang", "zhuang", "yellow", "purple"]
console.log(removed);//["huang"]
發(fā)現(xiàn):
- splice( )始終會返回一個數(shù)組焊虏。
- 返回的數(shù)組包含從原始數(shù)組中刪除的項,如果沒有刪除過秕磷,就會返回一個空數(shù)組诵闭。
5.2.7 位置方法
方法 | 功能 |
---|---|
indexOf( ) | 返回項在數(shù)組中的位置 |
lastIndexOf( ) | 同上 |
接受兩個參數(shù):第一個是要查找的項,第二個參數(shù)表示的是表示起點位置的索引澎嚣。
5.2.8 迭代方法
方法 | 功能 |
---|---|
every( ) | 對數(shù)組的每一項運行給定函數(shù)疏尿,全部是true就會返回true |
filter( ) | 對數(shù)組的每一項運行給點函數(shù),返回改函數(shù)會返回true的項組成的數(shù)組 |
foeEach( ) | 對數(shù)組的每一項運行給點函數(shù),無返回值 |
map( ) | 對數(shù)組的每一項運行給點函數(shù),返回每次調(diào)用函數(shù)的結(jié)果組成的數(shù)組 |
some( ) | 對數(shù)組的每一項運行給點函數(shù),如果該函數(shù)給任一項返回true易桃,則就會返回true |
//filter
var numbers = [1,2,3,4,5,4,3,2,1];
var filterResult = numbers.filter(function(item){
return (item >2);//[3, 4, 5, 4, 3]
});
console.log(filterResult);
//map
var numbers = [1,2,3,4,5,4,3,2,1];
var mapResult = numbers.map(function(item){
return item*2;
});
console.log(mapResult);//[2, 4, 6, 8, 10, 8, 6, 4, 2]
5.2.9 縮小方法
方法 | 功能 |
---|---|
reduce( ) | 迭代數(shù)組的所有項褥琐,然后構(gòu)建一個最終返回的值,從第一項開始 |
reduceRight( ) | 迭代數(shù)組的所有項晤郑,然后構(gòu)建一個最終返回的值敌呈,從最后一項開始 |
作為參數(shù)的函數(shù)接受4個參數(shù):前一個值,當(dāng)前值贩汉,項的索引和數(shù)組對象驱富。這個函數(shù)返回的任何值都會作為第一個參數(shù)自動傳給下一項。第一次迭代發(fā)生在數(shù)組的第二項匹舞,因此第一個參數(shù)是數(shù)組的第一項褐鸥,第二個參數(shù)就是數(shù)組的第二項。
var values =[1,2,3,4,5];
var sum = values.reduce(function(prev, cur, index, array){
return prev+cur;
});
console.log(sum);//15
5.3 Date類型
第六章 面向?qū)ο蟮某绦蛟O(shè)計
內(nèi)容:
- 理解對象屬性
- 理解并創(chuàng)建對象
- 理解繼承
6.1 理解對象
6.1.1 屬性類型
內(nèi)部才有的特性赐稽,用[[...]]來表示的叫榕。
1.數(shù)據(jù)屬性
屬性 | 描述 |
---|---|
[[Configurable]] | 能否delete刪除屬性從而重新定義、能否修改屬性的特性姊舵、能否把屬性修改為訪問器屬性晰绎。 |
[[Enumerable]] | 能否通過for-in枚舉。默認是true |
[[Eritable]] | 能否修改屬性的值 |
[[Value]] | 包含這個屬性的數(shù)據(jù)值 |
<script>
var person = {
name:"HuangZhuang";
}
</script>
如上所示:創(chuàng)建一個對象括丁,它的默認內(nèi)部屬性前三個都是true,然后[[value]]被設(shè)置成了一個特定的值HuangZhuang荞下。對象創(chuàng)建name屬性,[[Value]]被設(shè)置了史飞,在對name屬性值得任何時候的修改都會反映在這個位置尖昏。
修改特性的默認值,只能調(diào)用:
Object.defineProperty(屬性所在對象构资,"屬性名字"抽诉,"一個描述符對象")
如果要修改,則:
var person = {};
Object.defineProperty(person, "name", {
writable: false,
value: "hz"
})
console.log(person.name); //hz
person.name= "hh";
console.log(person.name); //hz
有一點注意:就是當(dāng)Configurable是false時吐绵,其他三個的特性是要受到限制的迹淌,而且設(shè)定Object.defineProperty后河绽,這四個特性均是默認設(shè)定成false的。
2.訪問器屬性
訪問器屬性不包含數(shù)組唉窃,但是包含一對getter和setter函數(shù)耙饰。
屬性 | 描述 |
---|---|
[[Configurable]] | 能否delete刪除屬性從而重新定義、能否修改屬性的特性句携、能否把屬性修改為訪問器屬性榔幸。 |
[[Enumerable]] | 能否通過for-in枚舉。默認是true |
[[Get]] | 讀取屬性時調(diào)用的函數(shù) |
[[Set]] | 寫入屬性時調(diào)用的函數(shù) |
訪問器屬性不可以直接定義矮嫉,必須通過Object.defineProperty( )來定義。
var book = {
_year : 2004,
edition: 1
};
Object.defineProperty(book, "year",{
get: function(){
return this._year;
},
set: function(newValue){
if(newValue > 2004){
this._year = newValue;
this.edition += newValue - 2004;
}
}
})
book.year = 2005;
alert(book.edition); //2
下劃線表示只能通過對象方法訪問的屬性牍疏。
6.1.2 定義多個屬性
Object.defineProperties(第一個對象是要添加和修改其屬性的對象蠢笋,第二個對象的屬性與第一個對象中要添加或修改的屬性一一對應(yīng))
6.1.3 讀取屬性的特性
一個函數(shù)Object.getOwnPropertyDescriptor( )針對屬性是數(shù)據(jù)類型還是訪問器類型返回出內(nèi)部屬性的值。
var a = Object.getOwnPropertyDescriptor(book, "year");
console.log(a);
6.2 創(chuàng)建對象
Object構(gòu)造函數(shù)或?qū)ο笞置媪慷伎梢詣?chuàng)建單個對象鳞陨,但是這種方式是有明顯的缺點的:使用同一個接口創(chuàng)建很多對象昨寞,會產(chǎn)生大量的額重復(fù)代碼。
6.2.1 工廠模式
用函數(shù)來封裝以特定的接口創(chuàng)建對象的細節(jié)厦滤。
function createPerson(name, age, job){
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function(){
console.log(this.name);
}
return o;
}
var o1 = createPerson("hz", 25, 'IT');
......
但是卻沒有解決對象識別的問題援岩,即怎樣知道一個對象的類型。
6.2.2 構(gòu)造函數(shù)模式
特點:
- 沒有顯示的創(chuàng)建對象
- 直接將屬性和方法賦值給this對象
- 沒有return語句
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = function(){
console.log(this.name);
}
};
var Person1 = new Person("hz", 25, "IT");
構(gòu)造函數(shù)始終都應(yīng)該以一個大寫字母開頭掏导,非構(gòu)造函數(shù)才是用小寫字母開頭享怀。
以上的例子中,要創(chuàng)建一個Person的新實例趟咆,要使用new操作符添瓷。經(jīng)理四個步驟:
- 1創(chuàng)建一個新對象。
- 2將構(gòu)造函數(shù)打的作用域賦值給新對象值纱,this就會指向新對象鳞贷。
- 3執(zhí)行構(gòu)造函數(shù)中的代碼。
- 4返回新對象虐唠。
Person創(chuàng)建的實例搀愧,都有一個指向Person的Constructor屬性。
console.log(Person1.constructor == Person ); //true
構(gòu)造函數(shù)與其他函數(shù)的唯一區(qū)別就是調(diào)用方式疆偿。new 操作符來調(diào)用函數(shù)就是構(gòu)造函數(shù)咱筛,如果沒有就和普通函數(shù)沒有區(qū)別的。
// 作為構(gòu)造函數(shù)使用
var person = new Person("hz", 25, "IT");
person.sayName();//hz
//作為普通函數(shù)使用
Person("hz", 25, "IT");//添加到window對象
window.sayName();
// 在另一個對象中使用
var o = new Object();
Person.call(o, "hz", 25, "IT"); //在o對象的特殊作用域中調(diào)用翁脆,o就擁有了所有屬性和方法眷蚓。
o.sayName();
構(gòu)造函數(shù)的問題就是每個方法都要在每個實例上重新創(chuàng)建一遍。就是說不同實例上的同名函數(shù)實際上是不一樣的反番。如果把這些方法通過全局作用域的函數(shù)調(diào)出來可以解決沙热,但是當(dāng)需要很多方法時叉钥,封裝性太差。解決方法:原型模式篙贸。
var Person1 = new Person("hz", 25, "IT");
var Person2 = new Person("hz", 25, "IT");
console.log(Person1.sayName == Person2.sayName); //false
1.理解原型對象
任何時候創(chuàng)建新函數(shù)投队,就會創(chuàng)建一個prototype屬性,這個屬性指向函數(shù)的原型對象爵川。默認情況下敷鸦,原型對象會自動獲得一個constructor屬性,這個屬性包含一個指向prototype屬性所在函數(shù)的指針寝贡。
雖然沒有辦法訪問到[[prototype]],但是通過isPrototypeOf( )方法可以確定對象之間是否存在這種關(guān)系扒披。如果[[prototype]]指向調(diào)用isPrototypeOf( )方法的對象,就會返回true圃泡。
console.log(Person.prototype.isPrototypeOf(person1)); //true
而ECMAScript5新增加的一個方法Object.getPrototypeOf( )返回的對象實際就是這個對象的原型碟案。Object.getPrototypeOf( )很方便的取得一個對象的原型。
console.log(Object.getPrototypeOf(person1) == Person.prototype); //true
幾點說明:
- 當(dāng)代碼讀到屬性時候颇蜡,就會進行一次搜索价说,先從實例開始,如果沒有搜到风秤,則就會繼續(xù)搜索指針指向的原型鳖目。
- 實例中重新定義新的屬性和方法不會改變原型中的屬性和方法,但是在調(diào)用該實例的時候會屏蔽原型的缤弦。
- delete刪除操作符可以完全刪除實例屬性领迈。從而可以重新訪問原型中的屬性。
- hasOwnPrototype( )檢測一個屬性是否存在實例中甸鸟,還是存在原型中惦费。這個方法是繼承過來的,只有在實例設(shè)定屬性或者方法的時候才會返回true抢韭;
2.原型與in操作符
- 單獨使用in的時候薪贫,會在對象能夠訪問給定屬性時返回true,實例和原型均可刻恭。
console.log("name" in person1); //true
通過hasOwnPrototype( )和in結(jié)合就可以封裝一個檢測屬性是實例還是原型中的函數(shù):
function hasPrototypeProperty(object, name){
return !Object.hasOwnProperty(name) && (name in object);
}
原理:只要in操作符返回true而且.hasOwnProperty( )返回false就可以判斷屬性是存在原型中的瞧省。
- for-in循環(huán),返回的是所有能夠通過對象訪問的鳍贾,可枚舉的屬性鞍匾。包括在實例中的屬性以及原型中的屬性。屏蔽了原型中不可枚舉屬性的實例屬性也會返回骑科。
Object.keys()方法可以返回所有可枚舉的實例屬性橡淑。參數(shù)如果是xxx.prototype則返回原型課枚舉的屬性。如果對于實例調(diào)用則只會返回實例的屬性和方法咆爽,不會返回原型的梁棠。
如果要得到所有屬性和方法置森,不管是不是可枚舉,則使用getOwnPrototypeNames()
var keys = Object.keys(Person.prototype);
console.log(keys);//["name", "age", "job", "sayName"];
var key = Object.getOwnPropertyNames(Person.prototype);
console.log(key);//["constructor", "name", "age", "job", "sayName"];
3.更簡單的原型方法
為減少不必要的代碼書寫符糊,可以使用如下的方法:
function Person(){}
Person.prototype = {
constructor : Person凫海,//一般沒有,是為了重新設(shè)置constructor才用設(shè)置男娄,但是會帶來問題行贪。
name : "hzhuang",
age : 25,
job : "IT",
sayName : function(){
console.log(this.name);
}
}
如上,Person.prototype設(shè)置成等于一個以對象字符量形式創(chuàng)建的新對象模闲。但是值得注意的是此時constructor不再指向Person建瘫。此時的語法是完全重寫了prototype對象,所以constructor屬性就指向l構(gòu)造函數(shù)Object尸折,不再是Person了暖混。如下:
var friend = new Person();
console.log(friend.constructor == Person);//false
console.log(friend.constructor == Object);//true
如果想重新設(shè)定回去(讓friend.constructor == Person是true),那么就要在這個對象字面量里面添加一組condtructor的鍵值對翁授。見3開始的例子。但是會帶來問題晾咪,會讓constructor屬性變成可枚舉的收擦。
在兼容ECMAScript5的引擎中,可以用Object.definePeoperty來解決這個問題谍倦。
Object.defineProperty(Person.prototype, "constructor", {
enumerable : false,
value : Person
})
4.原型的動態(tài)性
對原型對象所做的任何修改都可以立即在實例上反應(yīng)出來塞赂。即使是先創(chuàng)建實例然后修改原型。
但是如果是重寫原型昼蛀,情況就大不一樣了宴猾。調(diào)用構(gòu)造函數(shù)時會為實例添加一個執(zhí)行最初原型的[[prototype]]指針,而把原型修改成另一個對象就等于切斷了構(gòu)造函數(shù)與最初原型的聯(lián)系叼旋。實例中的指針只執(zhí)行原型仇哆,不指向構(gòu)造函數(shù)。
function Person(){}
var friend = new Person();
Person.prototype = {
constructor : Person,
name : "hzhuang",
age : 25,
job : "IT",
sayName : function(){
console.log(this.name);
}
}
friend.sayName();//Uncaught TypeError: friend.sayName is not a function
5.原生對象的原型
不建議修改原生對象的原型夫植。
6.原型對象的問題
- 省略了為構(gòu)造函數(shù)傳遞初始化參數(shù)這一環(huán)節(jié),結(jié)果所有實例在默認的情況下都將取得相同的屬性值。
- 最大的問題是有共享的本性造成的秩伞。
原型中的所有屬性都可以被很多實例共享涛酗,但是對于包含引用類型的屬性來說們就會出現(xiàn)很明顯的問題。
function Person(){}
Person.prototype = {
constructor : Person,
name : "hzhuang",
age : 25,
job : "IT",
friends : ["a", "b"],
sayName : function(){
console.log(this.name);
}
}
var person1 = new Person();
var person2 = new Person();
person1.friends.push("c");
console.log(person2.friends);//["a", "b", "c"]
問題好明顯沈跨,我只是修改了實例1的friends由捎,但是卻在所有的實例中反應(yīng)出來了《隽荩基于此狞玛,單獨的原型模式一般是不常用的软驰。
6.2.4 組合使用構(gòu)造函數(shù)模式和原型模式
- 構(gòu)造函數(shù)用于定于實例屬性;
- 原型模式用于定于方法和共享的屬性为居。
重寫之前有問題的例子:
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.friends = ["a", "b"];
}
Person.prototype = {
constructor : Person,
sayName : function(){
console.log(this.name);
}
}
可見這種混合模式的優(yōu)點:
- 每個實例都有自己的實例屬性的副本碌宴,同時又有共享的方法。
- 最大限度的節(jié)省了內(nèi)存
- 還支持構(gòu)造函數(shù)傳遞參數(shù)
6.2.5 動態(tài)原型模式
把所有的信息封裝在構(gòu)造函數(shù)中蒙畴,而通過在構(gòu)造函數(shù)中初始化原型贰镣,又保持了同時使用構(gòu)造函數(shù)和原型的優(yōu)點。就是說可以通過檢測某個應(yīng)該存在的方法是否有效膳凝,來決定是否需要初始化原型碑隆。
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.friends = ["a", "b"];
if(typeof this.sayName != "function"){
Person.prototype.sayName = function(){
console.log(this.name);
}
}
}
var friend = new Person("hzhuang", 25, "IT");
friend.sayName();
if( )部分只會在初次調(diào)用函數(shù)的時候執(zhí)行,之后原型就完成初始化蹬音。此時原型的修改都會反映在實例中上煤。
6.2.6 寄生構(gòu)造函數(shù)模式
創(chuàng)建一個函數(shù),這個函數(shù)的作用就是封裝創(chuàng)建對象的代碼著淆,然后再返回新創(chuàng)建的對象劫狠。和工廠模式一樣,區(qū)別只是這里是在一個函數(shù)里面并返回的這個對象永部。
6.2.7 穩(wěn)妥構(gòu)造函數(shù)模式
- 沒有公共屬性独泞。
- 也不用this對象。
function Person(name, age, job){
var o = new Object();
o.sayName = function(){
alert(name); //不使用this
}苔埋;
return o;
}
除了調(diào)用sayname( )方法外懦砂,沒有其他方法可以訪問到傳入到構(gòu)造函數(shù)中的原始數(shù)據(jù),保證了一種安全性组橄。
6.3 繼承
js沒有接口繼承荞膘,只支持實現(xiàn)繼承。
6.3.1 原型鏈
原型鏈是實現(xiàn)繼承的主要方法玉工。
基本思路:利用原型讓一個引用類型繼承另一個引用類型的屬性和方法羽资。
每個構(gòu)造函數(shù)都有一個原型對象,原型對象都包含一個指向構(gòu)造函數(shù)的指針瓮栗,而每個實例都包含一個指向原型函數(shù)對象的內(nèi)部指針削罩。如果將原型對象等于另一個類型的實例。則就會形成一個鏈费奸。
function SuperType(){
this.property = true;
};
SuperType.prototype.getSuperValue = function(){
return this.property;
};
function SubType(){
this.subproperty = false;
};
// 繼承SuperType( )
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function(){
return this.subproperty;
};
var instance = new SubType();
console.log(instance.getSuperValue());
幾點說明:
- instance.constructor指向SuperType弥激,因為SubType的原型重寫了。
- instance指向SubType的原型
- SubType的原型又指向SuperType的原型
1.別忘記默認的原型
所有的函數(shù)的默認原型都是Object的實例愿阐,因此默認原型都會包含一個內(nèi)部的指針微服,指向Object.prototype。這就是為什么函數(shù)可以繼承toString( )等默認方法的根本原因缨历。
2.確定原型和和實例的關(guān)系
兩種方式:
方式 | 描述 |
---|---|
instanceof | 只要用這個操作符來測試實例與原型鏈中出現(xiàn)的構(gòu)造函數(shù)以蕴,就會返回true糙麦。 |
isPrototypeOf( ) | 只要是原型鏈中出現(xiàn)過的原型,都可以說是該原生鏈所派生的實例的原型丛肮。 |
3.謹慎的定義方法
給原型添加方法的代碼一定要放在替換原型的語句之后赡磅。
必須在用要被繼承的構(gòu)造函數(shù)的實例替換當(dāng)前的原型之后,再定義方法宝与。
通過原型鏈實現(xiàn)繼承的時候焚廊,不能使用對象字面量創(chuàng)建原型方法。因為這樣會重寫原型鏈习劫。
// 繼承SuperType()
SubType.prototype = new SuperType();
SubType.prototype = {
getSubValue : function(){
return this.subproperty;
},
someOhterMethod : function(){
return false;
}
}
var instance = new SubType();
console.log(instance.getSuperValue()); //error
剛剛把SuperType的實例賦值給原型咆瘟,接著又將原型替換成一個對象字面量而導(dǎo)致的問題。由于現(xiàn)在的原型包含的是一個Object的實例诽里,而非SuperType的實例袒餐,因此我們設(shè)想的原型鏈已經(jīng)被切斷了。
4.原型鏈的問題
最大的問題是引用類型值的原型谤狡。還是共享問題灸眼。引用類型。
基于此墓懂,很少單獨使用原型鏈幢炸。
6.3.2 借用構(gòu)造函數(shù)
解決單獨原型鏈中引用類型帶來的問題,借用構(gòu)造函數(shù)的技術(shù)拒贱。
基本思想:在子類型構(gòu)造函數(shù)的內(nèi)部調(diào)用超類型構(gòu)造函數(shù)。函數(shù)是特定環(huán)境中執(zhí)行代碼的對象佛嬉,可以使用apply( )和call( )方法在新創(chuàng)建的對象上執(zhí)行構(gòu)造函數(shù)逻澳。
function SuperType(){
this.colors = ["red", "blue", "green"];
}
function SubType(){
//繼承SuperType
SuperType.call(this, "hzhaung");//hzhuang是傳遞的參數(shù)。
}
var instance1 = new SubType();
instance1.colors.push("blcak");
console.log(instance1.colors);//["red", "blue", "green", "blcak"]
var instance2 = new SubType();
console.log(instance2.colors);//["red", "blue", "green"]
在新SubType對象上執(zhí)行SuperType( )函數(shù)中定義的所有對象初始化代碼暖呕。
1.傳遞參數(shù)
2.借用構(gòu)造函數(shù)的問題
方法在構(gòu)造函數(shù)中定義斜做,所以就無法復(fù)用。
6.3.3 組合繼承
將原型鏈和借用構(gòu)造函數(shù)的技術(shù)組合在一起湾揽。
思路:使用原型鏈實現(xiàn)對原型屬性和方法的繼承瓤逼,而通過借用構(gòu)造函數(shù)來實現(xiàn)對實例屬性的繼承。這樣在原型上定義的方法實現(xiàn)了函數(shù)的復(fù)用库物,又可以保證每個實例有它自己的屬性霸旗。
function SuperType(name){
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
console.log(this.name);
}
function SubType(name, age){
//繼承SuperType
SuperType.call(this, name);
this.age = age;
}
SubType.prototype = new SuperType();
SubType.prototype.sayAge = function(){
console.log(this.age);
}
var instance1 = new SubType("hzhuang", 25);
instance1.colors.push("blcak");
console.log(instance1.colors);//["red", "blue", "green", "blcak"]
instance1.sayName();//hzhuang
instance1.sayAge();//25
var instance2 = new SubType("hz", 26);
instance2.sayName();//hz
instance2.sayAge();//26