javascript高級程序第三版學(xué)習(xí)筆記(持續(xù)更新)

題記

從[我的博客]中搬運過來的,主要的目的是用于自己學(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類型)
  • 第六章 面向?qū)ο蟪绦蛟O(shè)計

    • 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

6.3.4 原型式繼承

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市戚揭,隨后出現(xiàn)的幾起案子诱告,更是在濱河造成了極大的恐慌,老刑警劉巖民晒,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件精居,死亡現(xiàn)場離奇詭異锄禽,居然都是意外死亡,警方通過查閱死者的電腦和手機靴姿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門沃但,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人佛吓,你說我怎么就攤上這事宵晚。” “怎么了辈毯?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵坝疼,是天一觀的道長。 經(jīng)常有香客問我谆沃,道長钝凶,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任唁影,我火速辦了婚禮耕陷,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘据沈。我一直安慰自己哟沫,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布锌介。 她就那樣靜靜地躺著嗜诀,像睡著了一般。 火紅的嫁衣襯著肌膚如雪孔祸。 梳的紋絲不亂的頭發(fā)上隆敢,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天,我揣著相機與錄音崔慧,去河邊找鬼拂蝎。 笑死,一個胖子當(dāng)著我的面吹牛惶室,可吹牛的內(nèi)容都是我干的温自。 我是一名探鬼主播,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼皇钞,長吁一口氣:“原來是場噩夢啊……” “哼悼泌!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起夹界,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤券躁,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體也拜,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡以舒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了慢哈。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蔓钟。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖卵贱,靈堂內(nèi)的尸體忽然破棺而出滥沫,到底是詐尸還是另有隱情,我是刑警寧澤键俱,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布兰绣,位于F島的核電站,受9級特大地震影響编振,放射性物質(zhì)發(fā)生泄漏缀辩。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一踪央、第九天 我趴在偏房一處隱蔽的房頂上張望臀玄。 院中可真熱鬧,春花似錦畅蹂、人聲如沸健无。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽累贤。三九已至,卻和暖如春少漆,著一層夾襖步出監(jiān)牢的瞬間畦浓,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工检疫, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人祷嘶。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓屎媳,卻偏偏與公主長得像,于是被迫代替她去往敵國和親论巍。 傳聞我的和親對象是個殘疾皇子烛谊,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內(nèi)容