js高級程序設(shè)計讀書筆記

1. js介紹

js是為了實(shí)現(xiàn)網(wǎng)絡(luò)交互而是設(shè)計的腳本語言躲舌,有以下三部分組成

  • ECMAScript,由ECMA-262定義约计,提供核心功能,其實(shí)web瀏覽器是其宿主環(huán)境之一尉桩,組成部分:語法,類型这橙,語句屈扎,關(guān)鍵字筑凫,保留字滓技,操作符膝昆,對象
  • 文檔對象模型(DOM)荚孵,提供訪問和操作頁面的接口和方法,DOM把整個頁面映射為一個多層節(jié)點(diǎn)結(jié)構(gòu)判没,根據(jù)其提供的API,開發(fā)人員可自如增刪改換節(jié)點(diǎn)。
    DOM1=DOM Core(映射文檔結(jié)構(gòu)) + DOM html(對html的對象和方法)
    DOM2新模塊:
  1. DOM視圖(DOM views)俏竞,跟蹤不同文檔的視圖接口
    2 .DOM事件(DOM Events),定義事件和時間處理的接口
  2. DOM樣式(DOM style),基于CSS為元素應(yīng)用樣式接口
  3. DOM遍歷和范圍(DOM Traversal and Range),遍歷和操作文檔樹的接口
    DOM3新模塊:
    .DOM驗(yàn)證(DOM Validation)文檔驗(yàn)證方法并支持XML1.0規(guī)范
  • 瀏覽器對象模型(BOM)
    根本來說漱牵,處理瀏覽器的窗口和框架刁赦,但人們習(xí)慣將一下擴(kuò)展也算成BOM的一部分
    1.彈出新瀏覽器窗口
    2.移動 關(guān)閉 縮放瀏覽器
  1. 提供瀏覽器詳細(xì)信息的navigator對象
    4.瀏覽器所加載頁面的詳細(xì)信息location對象
    5.用戶顯示器分辨率信息screen對象
    6.對cookie的支持
    7.自定義對象

2.在html中使用js

通過<script>引入甚脉,常用屬性
1.async,表示應(yīng)該立即下載腳本猴凹,但不妨礙頁面的其他操作,會在頁面load之前進(jìn)行
2.defer爷绘,表示文檔可以延遲到文檔全部被解析和顯示后再執(zhí)行
3.src购对,執(zhí)行代碼的外部文件
4.type骡苞,表示編寫代碼使用的腳本語言的內(nèi)容類型(也成為MIME類型),一般是text/javascript(這個是默認(rèn)的)
使用方式
1.直接放入內(nèi)部元素亚铁,內(nèi)部/script應(yīng)替換成</script>,以免造成誤解
2.嵌入式
一般放在body后面,這樣在解析JS語言之前然爆,頁面內(nèi)容已經(jīng)完全展示在瀏覽器上曾雕,不要出現(xiàn)瀏覽器明顯延遲的問題
<noscript>在不支持js的瀏覽器顯示替代的內(nèi)容

3.基本概念

  • 標(biāo)識符
    駝峰大小寫格式切诀,如firstStudent
  • 注釋
    //單行
    /*
    *多行
    */
  • 嚴(yán)格模式
    "use strict"
  • 變量
    松散類型
var message; //沒初始化,因此是undefined

不使用var標(biāo)識符的話就是全局變量

  • 類型typeof
    undefined倒庵,boolean, string绍申,object剧腻,number灰伟,function
  • number:
    Infinity(正無窮)
    -Infinity(負(fù)無窮)
    isFinite()判斷是否有窮
    NaN非數(shù)值isNaN()判斷是否為數(shù)值
    將非數(shù)值轉(zhuǎn)化為數(shù)值
    Number parseInt parseFloat
  • object對象
    初始化 var o = new object();
    屬性方法
    Constructor創(chuàng)建當(dāng)前對象的函數(shù)
    hasOwnProperty(propertyName)給定的屬性在當(dāng)前實(shí)例中是否出現(xiàn)
    ** isPrototypeOf(object) **別傳入的對象是否為另一個對象的原型
    PropertyIsEnumerable判斷給定的屬性是否可以用 for...in 語句進(jìn)行枚舉。
    toLocaleString 方法返回執(zhí)行環(huán)境對應(yīng)的字符串挡爵。
    toString()對象字符串表示
    valueOf()返回對象的字符串?dāng)?shù)值或布爾表示
  • 語句
    if do-while while for switch
    for-in枚舉
    lable-代碼中添加標(biāo)簽茶鹃,以便后來使用?疗韵?蕉汪?
    break 跳出整個循環(huán) continue跳出當(dāng)前循環(huán)
    with 作用域設(shè)定到一個對象中

4.變量肤无,作用域竞漾,內(nèi)存問題

執(zhí)行環(huán)境類型——全局,局部
其中內(nèi)部環(huán)境可通過作用域鏈訪問所有的外部環(huán)境笔时,但外部環(huán)境不能內(nèi)部環(huán)境的任何變量和函數(shù)

4.1延長作用域鏈

執(zhí)行下列語句時,作用域延長

try-catch
with

  • 栗子1
function buildUrl(){  
     var qs="?debug=true";  
     with(location){  
         var url=href+qs;  
     }  
     return url;  
}  
var result=buildUrl();  
alert(result);  

輸出: 靜態(tài)頁地址+qs的值较锡。
原因:
1.由于with語句塊中作用域的‘變量對象’是只讀的,所以在他本層定義的標(biāo)識符,不能存儲到本層鸟整,而是存儲到它的上一層作用域
2.with代碼塊中,javascript引擎對變量的處理方式是:先查找是不是該對象的屬性兑燥,如果是,則停止除师。如果不是繼續(xù)查找是不是局部變量汛聚。

var o={href:"sssss"};  
var href="1111";  
function buildUrl(){  
     var qs="?debug=true";       
     with(o){  
          href="2222";  
          var url=href+qs;  
     }      
     return url;  
}  
var result=buildUrl();  
alert(result);  
alert(href);  

輸出: 結(jié)果:2222?debug=true + 1111

4.2 JavaScript作用域之沒有塊級作用域

<script>  
function test(o){  
    var i=0;  
    if(typeof o == "object"){  
        var j=0;  
        for(var k=0; k<10; k++){  
            document.writeln("k="+k);  
        }  
        document.writeln("k2="+k);  
    }     
    document.writeln("j="+j);     
}  
  
test(new String("pppp"));  
</script>  

輸出結(jié)果為:k=0 k=1 k=2 k=3 k=4 k=5 k=6 k=7 k=8 k=9 +++k=10 j=0
這是因?yàn)椋捎贘avaScript中不存在塊級作用域痕貌,因此函數(shù)中聲明的所有變量入宦,無論是在哪里聲明的落追,在整個函數(shù)中它們都有定義淋硝。

<script>  
var scope="global";  
function f(){  
    alert(scope);  
    var scope="local";  
    alert(scope);     
}  
  
f();  
</script> 

結(jié)果:第一個alert輸出:underfined而不是global竿报,第二個alert輸出local
與下列函數(shù)等價

function f(){  
    var scope;  
    alert(scope);  
    var scope="local";  
    alert(scope);         
}  

5.引用類型

5.1Object類型

創(chuàng)建有兩種方式:
1.new操作符后跟Object構(gòu)造函數(shù)

var person = new Object();
person.name = "Nicholas";
person.age = 29;

2.字面量表示法

var person = {
    name: "Nicholas",
    age: 20,
    5:true
};

這里所有的數(shù)值屬性名都會被轉(zhuǎn)換為字符串
訪問方法

alert(person.name);
alert(person[name])

5.2Arrary類型

構(gòu)造
var colors = ["red","green"];
var arrays = new Array(3);//new可省略
var names = new Array["Mia"];
數(shù)組尾部添加新項(xiàng)
colors[colors.length] = "pink"

js判斷數(shù)組類型的方法
  • instanceof
var a=[];
console.log(a instanceof Array) //返回true 
  • constructor
    constructor 屬性返回對創(chuàng)建此對象的數(shù)組函數(shù)的引用
console.log([].constructor == Array);
console.log({}.constructor == Object);
console.log("string".constructor == String);
console.log((123).constructor == Number);
console.log(true.constructor == Boolean);

較為嚴(yán)謹(jǐn)并且通用的方法:

function isArray(object){
    return object && typeof object==='object' &&
            Array == object.constructor;
}

A揖阵幸!注意:

使用instaceof和construcor,被判斷的array必須是在當(dāng)前頁面聲明的!比如芽世,一個頁面(父頁面)有一個框架挚赊,框架中引用了一個頁面(子頁面),在子頁面中聲明了一個array济瓢,并將其賦值給父頁面的一個變量,這時判斷該變量嚎朽,Array == object.constructor;會返回false融撞;
原因:
1当辐、array屬于引用型數(shù)據(jù),在傳遞過程中急鳄,僅僅是引用地址的傳遞。
2、每個頁面的Array原生對象所引用的地址是不一樣的励稳,在子頁面聲明的array,所對應(yīng)的構(gòu)造函數(shù)讲逛,是子頁面的Array對象;父頁面來進(jìn)行判斷技羔,使用的Array并不等于子頁面的Array榄攀;切記趁曼,不然很難跟蹤問題射众!

  • 特性判斷法
function isArray(object){
    return  object && typeof object==='object' &&    
            typeof object.length==='number' &&  
            typeof object.splice==='function' &&    
             //判斷l(xiāng)ength屬性是否是可枚舉的 對于數(shù)組 將得到false  
            !(object.propertyIsEnumerable('length'));
}

有l(wèi)ength和splice并不一定是數(shù)組,因?yàn)榭梢詾閷ο筇砑訉傩裕荒苊杜elength屬性,才是最重要的判斷因子。備注:如果 proName 存在于 object 中且可以使用一個 For…In 循環(huán)窮舉出來辩块,那么 propertyIsEnumerable 屬性返回 true

  • 最簡單的方法
function isArray(o) {
    return Object.prototype.toString.call(o) === ‘[object Array]‘;
}

轉(zhuǎn)化方法

  • arrayObject.toLocaleString()
    返回值:
    arrayObject 的本地字符串表示。
  • toString()
    把數(shù)組轉(zhuǎn)換為字符串,并返回結(jié)果猛拴。返回值與沒有參數(shù)的 join() 方法返回的字符串相同芳室。
    alert(colors.join(","))
  • valueOf
    valueOf()方法返回 Array 對象的原始值伍宦。實(shí)際上势篡,為了創(chuàng)建這個字符串會調(diào)用數(shù)組的每一項(xiàng)的toString()方法齿尽。

棧方法

棧是一種LIFO(Last-In-First-Out,后進(jìn)先出)的數(shù)據(jù)結(jié)構(gòu)ECMAScript為數(shù)組提供了push()和pop()方法灯节,可以實(shí)現(xiàn)類似棧的行為循头。分別添加到數(shù)組末尾和從數(shù)組末尾移除最后一項(xiàng)。

隊(duì)列方法

shift:從數(shù)組中把第一個元素刪除炎疆,并返回這個元素的值卡骂。
unshift: 在數(shù)組的開頭添加一個或更多元素,并返回新的長度
push:在數(shù)組的中末尾添加元素形入,并返回新的長度
pop:從數(shù)組中把最后一個元素刪除偿警,并返回這個元素的值。

unshift比push要慢差不多100倍!因此螟蒸,平時還是要慎用unshift,特別是對大數(shù)組七嫌。那如果一定要達(dá)到unshift的效果,可以借助于Array的reverse方法诵原,Array的reverse的方法能夠把一個數(shù)組反轉(zhuǎn)。先把要放進(jìn)數(shù)組的元素用push添加陨收,再執(zhí)行一次reverse

重排序方法

reverse()——反轉(zhuǎn)
sort()——升序排列數(shù)組

操作方法

  • concat()方法
    基于當(dāng)前數(shù)組中所有項(xiàng)創(chuàng)建新數(shù)組。
var colors = ["red","green","blue"];
var colors2 = colors.concat("yellow",["black","brown"]);

alert(colors);
alert(colors2);

結(jié)果為colors為數(shù)組[“red”,”green”,”blue”];
colors2為數(shù)組[“red”,”green”,”blue”,”yellow”,”black”,”brown”];
concat()方法只是用當(dāng)前數(shù)組重新創(chuàng)建一個新的數(shù)組鸵赖,因此當(dāng)前數(shù)組保持不變(colors數(shù)組不變

  • slice()方法
    slice()方法:基于當(dāng)前數(shù)組中的一個或多個項(xiàng)創(chuàng)建一個新數(shù)組务漩。
    slice()方法中可以有一個或者兩個參數(shù)(代表數(shù)組的索引值拄衰,0,1,2……)。
    接收一個參數(shù)時:返回當(dāng)前數(shù)組中從此參數(shù)位置開始到當(dāng)前數(shù)組末尾間所有項(xiàng)菲饼。
    接收兩個參數(shù)時:返回當(dāng)前數(shù)組中兩個參數(shù)位置間的所有項(xiàng)肾砂,但不返回第二個參數(shù)位置的項(xiàng)列赎。
    參數(shù)也可以為負(fù)數(shù)宏悦,表示從末尾算起,-1代表最后一個包吝,使用方法和正數(shù)一樣饼煞。
var colors = ["red","green","blue","yellow","black","brown"];
var colors2 = colors.slice(2);
var colors3 = colors.slice(1,4);
var colors4 = colors.slice(2,-2);
var colors5 = colors.slice(-3,-1);

console.log(colors2);
console.log(colors3);
console.log(colors4);
console.log(colors5);

結(jié)果為:
[“blue”, “yellow”, “black”, “brown”]
[“green”, “blue”, “yellow”]
[“blue”, “yellow”]
[“yellow”, “black”]

  • splice()
    splice()主要用途是向當(dāng)前數(shù)組的中間插入項(xiàng),可以進(jìn)行刪除诗越、插入砖瞧、替換操作。會返回一個數(shù)組嚷狞,包含從原始項(xiàng)中刪除的項(xiàng)(若果沒有刪除块促,返回一個空數(shù)組)

刪除:兩個參數(shù),刪除起始項(xiàng)的位置和刪除的項(xiàng)數(shù)床未。

var colors = ["red","green","blue"];
var removed = colors.splice(1,2);
alert(colors);      //red
alert(removed);     //green,blue

插入:在指定位置插入任意數(shù)量項(xiàng)竭翠,包括兩個基本參數(shù)(即刪除操作中的兩個參數(shù)類型)和要插入項(xiàng)的參數(shù),兩個基本參數(shù)為起始位置和0(要刪除的項(xiàng)數(shù)應(yīng)為0項(xiàng))薇搁,要插入的項(xiàng)參數(shù)可以是任意個(”red”,”green”,”blue”)斋扰。

var colors = ["red","green","blue"];
var removed = colors.splice(1,0,"yellow","orange");
alert(colors);      //"red","yellow","orange","green","blue"
alert(removed);     //空數(shù)組

替換:向指定位置插入任意數(shù)量的項(xiàng)同時刪除任意數(shù)量的項(xiàng),插入項(xiàng)數(shù)和刪除項(xiàng)數(shù)可以不同啃洋。參數(shù)包括兩個基本參數(shù)(即刪除操作中的兩個參數(shù)類型)和要插入項(xiàng)的參數(shù)传货。

var colors = ["red","green","blue"];
var removed = colors.splice(1,1,"purple","black");
alert(colors);    //"red","purple","black","blue"
alert(removed);   //"green"                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  

位置方法

  • indexOf() 方法
    返回某個指定的字符串值在字符串中首次出現(xiàn)的位置。

  • lastIndexOf() 方法
    返回一個指定的字符串值最后出現(xiàn)的位置宏娄,在一個字符串中的指定位置從后向前搜索问裕。

  • substr
    substr(start,length)表示從start位置開始,截取length長度的字符串孵坚。
    var src="images/off_1.png";
    alert(src.substr(7,3));
    彈出值為:off

  • substring
    substring(start,end)表示從start到end之間的字符串僻澎,包括start位置的字符但是不包括end位置的字符。
    var src="images/off_1.png";
    alert(src.substring(7,10));
    彈出值為:off

迭代方法

var arr = [3,4,5,6,7,"a"];
var isNum = function(elem,index,AAA){
return !isNaN(elem);
}
var toUpperCase = function(elem){
return String.prototype.toUpperCase.apply(elem);
}
var print = function(elem,index){
console.log(index+"."+elem);
}
  • every
    對數(shù)組中的每一項(xiàng)執(zhí)行測試函數(shù)十饥,直到獲得對指定的函數(shù)返回 false 的項(xiàng)窟勃。使用此方法 可確定數(shù)組中的所有項(xiàng)是否滿足某一條件,類似于&&的含義
var res = arr.every(isNum);
console.log(res);//false;
  • some
    對數(shù)組中的每一項(xiàng)執(zhí)行測試函數(shù),直到獲得返回 true 的項(xiàng)逗堵。 使用此方法確定數(shù)組中的所有項(xiàng)是否滿足條件.類似于||的含義
res = arr.some(isNum);
console.log(res);//true
  • filter
    對數(shù)組中的每一項(xiàng)執(zhí)行測試函數(shù)秉氧,并構(gòu)造一個新數(shù)組,返回 true的項(xiàng)被添加進(jìn)新數(shù)組蜒秤。 如果某項(xiàng)返回 false汁咏,則新數(shù)組中將不包含此項(xiàng)
res = arr.filter(isNum);
console.log(res);//[3, 4, 5, 6, 7]
  • map
    對數(shù)組中的每一項(xiàng)執(zhí)行函數(shù)并構(gòu)造一個新數(shù)組亚斋,并將原始數(shù)組中的每一項(xiàng)的函數(shù)結(jié)添加進(jìn)新數(shù)組。
res = arr.map(toUpperCase);
console.log(res);//["3", "4", "5", "6", "7", "A"]
  • forEach
    對數(shù)組中的每一項(xiàng)執(zhí)行函數(shù),不返回值
res = arr.forEach(print);
console.log(res);

縮小方法

  • reduce
array.reduce(callbackfn,[initialValue])
function callbackfn(preValue,curValue,index,array){}

**preValue
**: 上一次調(diào)用回調(diào)返回的值攘滩,或者是提供的初始值(initialValue)
**curValue
**: 數(shù)組中當(dāng)前被處理的數(shù)組項(xiàng)
**index
**: 當(dāng)前數(shù)組項(xiàng)在數(shù)組中的索引值
**array
**: 調(diào)用 reduce()

Date類型

Date.parse接受一個字符串參數(shù)帅刊,如果可以轉(zhuǎn)化,將轉(zhuǎn)換為對應(yīng)的毫秒數(shù)漂问,否則返回 NaN赖瞒;
Date.UTC最少接受兩個參數(shù),分別表示年份和月份(0·11)蚤假,其他的日期栏饮,小時(0-24)、分鐘磷仰、秒袍嬉,可以指定也可以不指定,不指定時默認(rèn)為 0灶平;

dateObject.getTime() 0~... 從GTM1970年1月1日0:00:00開始計算的毫秒數(shù)伺通。
dateObject.getYear() 70~... 指定的年份減去1900,2000年后為4位數(shù)表示的年份逢享。
dateObject.getFullYear() 1970~... 4位數(shù)年份罐监,適用于版本4以上的瀏覽器。
dateObject.getMonth() 0~11 一年中的月份(1月為0)拼苍。
dateObject.getDate() 1~31 一月中的日期笑诅。
dateObject.getDay() 0~6 星期(星期日為0)。
dateObject.getHours() 0~23 一天中指定的小時數(shù)疮鲫,采用24小時制吆你。
dateObject.getMinutes() 0~59 指定小時內(nèi)的分鐘數(shù)。
dateObject.getSeconds() 0~59 指定分鐘內(nèi)的秒數(shù)俊犯。
dateObject.setTime(val) 0~... 從GTM1970年1月1日0:00:00開始計算的毫秒數(shù)妇多。
dateObject.setYear(val) 70~... 指定的年份減去1900,2000年后為4位數(shù)表示的年份燕侠。
dateObject.setMonth(val) 0~11 一年中的月份(1月為0)者祖。
dateObject.setDate(val) 1~31 一月中的日期。
dateObject.setDay(val) 0~6 星期(星期日為0)绢彤。
dateObject.setHours(val) 0~23 一天中的小時數(shù)七问,采用24小時值。
dateObject.setMinutes(val) 0~59 指定小時內(nèi)的分鐘數(shù)茫舶。
dateObject.setSecond(val) 0~59 指定小時內(nèi)的秒數(shù)械巡。

當(dāng)前時間

var start = Date.now()

格式化

var d = new Date();
console.log(d); // 輸出:Mon Nov 04 2013 21:50:33 GMT+0800 (中國標(biāo)準(zhǔn)時間)
console.log(d.toDateString()); // 日期字符串,輸出:Mon Nov 04 2013
console.log(d.toGMTString()); // 格林威治時間,輸出:Mon, 04 Nov 2013 14:03:05 GMT
console.log(d.toISOString()); // 國際標(biāo)準(zhǔn)組織(ISO)格式讥耗,輸出:2013-11-04T14:03:05.420Z
console.log(d.toJSON()); // 輸出:2013-11-04T14:03:05.420Z
console.log(d.toLocaleDateString()); // 轉(zhuǎn)換為本地日期格式有勾,視環(huán)境而定,輸出:2013年11月4日
console.log(d.toLocaleString()); // 轉(zhuǎn)換為本地日期和時間格式古程,視環(huán)境而定蔼卡,輸出:2013年11月4日 下午10:03:05
console.log(d.toLocaleTimeString()); // 轉(zhuǎn)換為本地時間格式,視環(huán)境而定挣磨,輸出:下午10:03:05
console.log(d.toString()); // 轉(zhuǎn)換為字符串雇逞,輸出:Mon Nov 04 2013 22:03:05 GMT+0800 (中國標(biāo)準(zhǔn)時間)
console.log(d.toTimeString()); // 轉(zhuǎn)換為時間字符串,輸出:22:03:05 GMT+0800 (中國標(biāo)準(zhǔn)時間)
console.log(d.toUTCString()); // 轉(zhuǎn)換為世界時間趋急,輸出:Mon, 04 Nov 2013 14:03:05 GMT

RegExp

RegExp詳談

function

函數(shù)內(nèi)部屬性只要包括兩個特殊的對象:arguments和this喝峦。
函數(shù)屬性包括:length和prototype
函數(shù)方法(非繼承)包括:apply()和call()
繼承而來的函數(shù)方法:bind()势誊、toString()呜达、toLocaleString()、valueOf()

  • 沒有重載
    js不存在重載的概念粟耻,后面的方法會覆蓋先前的同名的方法查近。
  • 函數(shù)聲明和函數(shù)表達(dá)式
    1)函數(shù)聲明(Function Declaration);
    // 函數(shù)聲明
    function funDeclaration(type){
        return type==="Declaration";
    }

2)函數(shù)表達(dá)式(Function Expression)。

    // 函數(shù)表達(dá)式
    var funExpression = function(type){
        return type==="Expression";
    }

上面的代碼看起來很類似挤忙,感覺也沒什么太大差別霜威。但實(shí)際上,Javascript函數(shù)上的一個“陷阱”就體現(xiàn)在Javascript兩種類型的函數(shù)定義上册烈。下面看兩段代碼:

     funDeclaration("Declaration");//=> true
     function funDeclaration(type){
         return type==="Declaration";
     }
     funExpression("Expression");//=>error
     var funExpression = function(type){
         return type==="Expression";
     }

用函數(shù)聲明創(chuàng)建的函數(shù)funDeclaration可以在funDeclaration定義之前就進(jìn)行調(diào)用戈泼;而用函數(shù)表達(dá)式創(chuàng)建的funExpression函數(shù)不能在funExpression被賦值之前進(jìn)行調(diào)用。
代碼1段JS函數(shù)等同于:

    function funDeclaration(type){
        return type==="Declaration";
    }
    funDeclaration("Declaration");//=> true

代碼2段JS函數(shù)等同于:

    var funExpression;
    funExpression("Expression");//==>error
    funExpression = function(type){
        return type==="Expression";
    }

再來個例子

var sayHello;
    console.log(typeof (sayHey));//=>function    
    console.log(typeof (sayHo));//=>undefined
    if (true) {
        function sayHey() {
            console.log("sayHey");
        }
        sayHello = function sayHo() {
            console.log("sayHello");
    }
    } else {
        function sayHey() {
            console.log("sayHey2");
        }
        sayHello = function sayHo() {
            console.log("sayHello2");
        }
    }    
    sayHey();// => sayHey2    
    sayHello();// => sayHello

等同于

var sayHello;
    function sayHey() {
            console.log("sayHey");
        }
    function sayHey() {
            console.log("sayHey2");
    }
    console.log(typeof (sayHey));//=>function    
    console.log(typeof (sayHo));//=>undefined
    if (true) {
        //hoisting...
        sayHello = function sayHo() {
            console.log("sayHello");
    }
    } else {
        //hoisting...
        sayHello = function sayHo() {
            console.log("sayHello2");
        }
    }    
    sayHey();// => sayHey2    
    sayHello();// => sayHello

Javascript 中函數(shù)聲明和函數(shù)表達(dá)式是存在區(qū)別的赏僧,函數(shù)聲明在JS解析時進(jìn)行函數(shù)提升大猛,因此在同一個作用域內(nèi),不管函數(shù)聲明在哪里定義淀零,該函數(shù)都可以進(jìn)行調(diào)用挽绩。而函數(shù)表達(dá)式的值是在JS運(yùn)行時確定,并且在表達(dá)式賦值完成后驾中,該函數(shù)才能調(diào)用唉堪。這個微小的區(qū)別,可能會導(dǎo)致JS代碼出現(xiàn)意想不到的bug,讓你陷入莫名的陷阱中肩民。

  • 函數(shù)的內(nèi)部屬性
  • arguments
    有兩個特殊的對象:arguments和this唠亚。其中,arguments它是一個類數(shù)組對象持痰,包含著傳入函數(shù)中的所有參數(shù)灶搜。雖然arguments的主要用途是保存函數(shù)參數(shù),但這個對象含所有一個名叫callee的屬性,該屬性是一個指針占调,指向擁有這個arguments對象的函數(shù)暂题。
    下面這個非常經(jīng)典的階乘函數(shù)。
function factorial (num){
  if(num <= 1){
    return 1;
  } else{
  return num * factorial(num-1); 
  }
}

定義階乘函數(shù)一般都會用到遞歸算法究珊,如上面代碼所示薪者,在有函數(shù)名字,并且函數(shù)名字以后也不會改變的情況下剿涮,這種定義沒問題言津。但是這個函數(shù)的執(zhí)行與函數(shù)名factorial緊緊耦合在了一起,為了消除這種緊密耦合現(xiàn)象(函數(shù)名字改變等情況)取试,可以使用arguments.callee悬槽。

function factorial(num){
if(num<=1){
  return 1;
  } else{
    return num * arguments.callee(num-1);
  }
}

在這個重寫后的factorial()函數(shù)的函數(shù)體內(nèi)彩扔,沒有再引用函數(shù)名factorial墙杯。這樣话侄,無論引用函數(shù)時使用的是什么名字捻撑,都可以保證正常完成遞歸調(diào)用习瑰。例如:

var trueFactorial=factorial;
factorial=function()
{
    return 0;
};
 
alert(trueFactorial(5));//120
alert(factorial(5));//0

在此沉迹,變量trueFactorial獲得了factorial的值抽高,實(shí)際上是另一個位置上保存了一個函數(shù)的指針皆辽。然后萨赁,我們又將一個簡單的返回了0的函數(shù)賦值給了factorial變量弊琴。如果像原來factorial()那樣不用使用arguments.callee,調(diào)用trueFactorial()就會返回0杖爽∏枚可是,在解除了函數(shù)體內(nèi)的代碼與函數(shù)名的耦合狀態(tài)之后慰安,trueFactorial()仍然能夠正常的計算階乘腋寨;至于factorial(),它現(xiàn)在只是一個返回0的函數(shù)泻帮。

  • this
     函數(shù)內(nèi)部的另一個特殊對象是this精置,其行為與java和c#中的this大致類似。換句話說锣杂,this引用的是函數(shù)據(jù)以執(zhí)行的環(huán)境對象脂倦,或則也可以說是this值(當(dāng)在網(wǎng)頁的全局作用中調(diào)用函數(shù)時,this對象引用的就是window)元莫。如下例子:
window.color="red";
var o={color:"blue"};
 
function sayColor()
{
    alert(this.color);
}
sayColor();//red
 
o.sayColor=sayColor;
o.sayColor();//blue
  • apply()方法
    接收兩個參數(shù):一個是在其中運(yùn)行函數(shù)的作用域赖阻,另一個是參數(shù)數(shù)組。其中踱蠢,第二個參數(shù)可以使Array的實(shí)例火欧,也可以是arguments對象
unction sum(num1,num2)
{
    return num1+num2;
}
 
function callSum1(num1,num2)
{
    return sum.apply(this,arguments);//傳入arguments對象
}
 
function callSum2(num1,num2)
{
    return sum.apply(this,[num1,num2]);//傳入數(shù)組
}
 
alert(callSum1(10,10));//20
alert(callSum2(10,10));//20
  • call()方法
    對于call()方法而言棋电,第一個參數(shù)是this值沒有變化,變化的是其余參數(shù)都直接傳遞給函數(shù)苇侵。換句話講赶盔,在使用call()方法時,傳遞給函數(shù)的參數(shù)必須逐個列舉出來榆浓,如下例子:
function sum(num1,num2)
{
    return num1+num2;
}
 
function callSum(num1,num2)
{
    return sum.call(this,num1,num2);
}
 
alert(callSum(10,10));//20

事實(shí)上于未,傳遞參數(shù)并非apply()和call()正真的用武之地;它們正真強(qiáng)大的地方是能夠擴(kuò)充函數(shù)賴以運(yùn)行的作用域陡鹃。如下例子:

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

這一次烘浦,sayColor()也是作為全局函數(shù)定義的,而且當(dāng)在全局作用域中調(diào)用它時萍鲸,它確實(shí)會顯示“red”,因?yàn)閷his.color的求值會轉(zhuǎn)換成對window.color的求值脊阴。而sayColor.call(this)和sayColor.call(window)握侧,則是兩種顯示的在全局作用域中調(diào)用函數(shù)的方式,結(jié)果當(dāng)然都會顯示“red”蹬叭。但是藕咏,當(dāng)運(yùn)行sayColor.call(o)時状知,函數(shù)的執(zhí)行環(huán)境就不一樣了秽五,因?yàn)榇藭r函數(shù)體內(nèi)的this對象指向了o,于是結(jié)果顯示的是“blue”饥悴。
使用call()或apply()來擴(kuò)充作用域的最大好處坦喘,就是對象不需要與方法有任何耦合關(guān)系。在前面例子的第一個版本中西设,我們是先將sayColor()函數(shù)放到了對象o中瓣铣,然后再通過o來調(diào)用它;而在這里重寫的例子中贷揽,就不需要先前那個多余的步驟了棠笑。

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

在這里,sayColor()調(diào)用bind()并傳入對象o禽绪,創(chuàng)建了objectSayColor()函數(shù)蓖救。objectSayColor()函數(shù)的this值等于o,因此即使是在全局作用域中調(diào)用這個函數(shù)印屁,也會看到“blue”循捺。

函數(shù)表達(dá)式

理解作用域鏈?zhǔn)抢斫忾]包的關(guān)鍵;

(1)什么是執(zhí)行環(huán)境

執(zhí)行環(huán)境有二種: 全局執(zhí)行環(huán)境雄人;局部執(zhí)行環(huán)境---function里面;

執(zhí)行流進(jìn)入函數(shù)執(zhí)行時,創(chuàng)建執(zhí)行環(huán)境恰力;函數(shù)執(zhí)行結(jié)束叉谜,回收!

(2)變量對象

理解變量對象非常重要,變量對象在函數(shù)中也稱為 活動對象踩萎,我還是喜歡說成變量對象正罢。

每一個執(zhí)行環(huán)境都有一個變量對象,變量對象會保存這個執(zhí)行環(huán)境的變量和方法驻民;我們不難想到全局的變量對象是誰? window對象

我們在全局中添加變量和方法都是添加到window里翻具。函數(shù)執(zhí)行時 執(zhí)行環(huán)境中就會創(chuàng)建變量對象;一般來說:函數(shù)調(diào)用完畢之后無論是執(zhí)行環(huán)境(出棧)回还,還是變量對象都是回收的裆泳。閉包的出現(xiàn)使得變量對象不回收;

(3)作用域鏈?

什么是作用域鏈:作用域鏈的本質(zhì)是 指向變量對象的一組有序指針柠硕;字面上很難理解工禾,我第一次看不明白!

有什么作用:在一個執(zhí)行環(huán)境中對變量和方法進(jìn)行有序(正確)訪問;

什么時候創(chuàng)建: 一個函數(shù)聲明的時候就創(chuàng)建了蝗柔,作用域鏈會保存在一個函數(shù)的內(nèi)部屬性[[Scope]]中;

注意:執(zhí)行流進(jìn)入函數(shù)是: 創(chuàng)建執(zhí)行環(huán)境->將作用域鏈(利用[[Scope]]屬性) 復(fù)制到執(zhí)行環(huán)境中->創(chuàng)建變量對象(活動對象)->將變量對象的引用(指針)導(dǎo)入作用域鏈的最前端->執(zhí)行代碼

具體請看下面的代碼

  function compare(value1,value2){
         if(value1<value2){return 1;}
          else if(value1>value2){return -1;}
          else{return 0;}
       }
      var result=compare(5,10)//1

我們可以看到闻葵,作用域鏈?zhǔn)鞘裁?有序指針,前面說的作用域最前端在就是0位置癣丧。 查找變量或者函數(shù)是最前端開始的槽畔,0指向的活動對象沒有你要找的變量,再去1找胁编。0-1其實(shí)

從代碼的角度上看其實(shí)就是從函數(shù)內(nèi)部一直向函數(shù)外部找標(biāo)識符(變量或者函數(shù))厢钧,找到立即停止,不會再向上查找嬉橙。這就是作用域鏈!

  • 閉包
    定義: 閉包是有權(quán)訪問另外一個函數(shù)作用域變量的函數(shù)早直;注意閉包是一個函數(shù)!
    創(chuàng)建閉包的主要的方法:在一個函數(shù)里面創(chuàng)建一個函數(shù)(閉包); 比如
<script type="text/javascript">
    function A(value){
     var num=value;
    return function(){ //閉包
     alert(num);
  }
}
var B = A(0);
alert(B()); //0
</script>

在這里匿名函數(shù)是一個閉包市框,一般情況下: 一個函數(shù)執(zhí)行完畢之后霞扬,無論是作用域鏈還是變量對象都會回收,但是這個匿名函數(shù)的作用域鏈里有A()變量對象的引用枫振,所以沒有消除喻圃。

還可以訪問變量對象的num;這就是閉包的好處蒋得!但是閉包的出現(xiàn)加大內(nèi)存負(fù)擔(dān)级及,就這里而已,我們即使后面不再使用B函數(shù)了额衙,A()變量對象也不會消失饮焦,javascript不知道你什么時候還會再用怕吴,當(dāng)然我們可以這樣 B=null; 這樣的話匿名函數(shù)沒有引用,被回收县踢,A()變量對象也一起回收!

《javascript高級程序設(shè)計》中尼古拉斯大神建議我們:可以不使用閉包盡量不使用转绷,萬不得已才使用!

  • 塊級作用域

    我們都知道javascript是沒有塊級作用域的,比如{}; if(i=0){} while(){} for(){}這些都不會形成塊級作用域硼啤; 那么怎么創(chuàng)建 java c#類似功能的塊級作用域?

    語法:

(function(){

//塊級作用域

})();

注意: 我們創(chuàng)建一個匿名函數(shù)议经,立即調(diào)用,里面的代碼都要運(yùn)行一遍谴返,而在window中看不見煞肾,這不就是塊級作用域嗎? 還有一個好處嗓袱,這個匿名函數(shù)沒有指針籍救,

調(diào)用后回收,不會產(chǎn)生垃圾(里面的方法渠抹,變量都不需要再訪問的)蝙昙。簡直就是完美的塊級作用域! 注意格式 (匿名函數(shù))其實(shí)就是一個指針,再加上()就是調(diào)用了。

  • 構(gòu)造函數(shù)中的閉包

    (1) 我們知道怎么為對象添加'私有變量' 這樣

function Person(name,age){
    this.name=name;//共有屬性
    this.age=age;
    
    var school="一中"; //私有屬性
    this.GetSchool=function (){return school;}
}

我們這個school是私有的變量梧却,因?yàn)殚]包的原因, 對象實(shí)例自然可以訪問這個變量; 比如 var p=new Person('nos',20); p.GetSchool(); // 一中;

 (2)現(xiàn)在來一個奇葩: 靜態(tài)私有屬性 ;
(function(){

         var school=""; //靜態(tài)私有;

        Person=function(name,age,value){ //構(gòu)造函數(shù)

         this.name=name;this.age=age;

          school=value;

     }; 

    Person.prototype.GetSchool=function(){alert(school);}

         })();
      var p=new Person('andy',21,'一中');
      p.GetSchool();//一中
      var pp=new Person('nos',29,'二中');
      pp.GetSchool();//二中
      p.GetSchool();//二中

從結(jié)果上看 school是對象共有的奇颠,私有的屬性, 即靜態(tài)私有屬性;
我們看看構(gòu)造函數(shù)是怎么定義的: 沒有使用var ,前面說過即使在函數(shù)里面定義放航,沒有使用var申明烈拒,就是window的,為全局的三椿。自然可以在全局使用!

  這個匿名函數(shù)中調(diào)用了一次缺菌,只產(chǎn)生一個對象變量,school都是同一個搜锰,實(shí)現(xiàn)共享。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末耿战,一起剝皮案震驚了整個濱河市蛋叼,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌剂陡,老刑警劉巖狈涮,帶你破解...
    沈念sama閱讀 216,744評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異鸭栖,居然都是意外死亡歌馍,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評論 3 392
  • 文/潘曉璐 我一進(jìn)店門晕鹊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來松却,“玉大人暴浦,你說我怎么就攤上這事∠停” “怎么了歌焦?”我有些...
    開封第一講書人閱讀 163,105評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長砚哆。 經(jīng)常有香客問我独撇,道長,這世上最難降的妖魔是什么躁锁? 我笑而不...
    開封第一講書人閱讀 58,242評論 1 292
  • 正文 為了忘掉前任纷铣,我火速辦了婚禮,結(jié)果婚禮上战转,老公的妹妹穿的比我還像新娘关炼。我一直安慰自己,他們只是感情好匣吊,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,269評論 6 389
  • 文/花漫 我一把揭開白布儒拂。 她就那樣靜靜地躺著,像睡著了一般色鸳。 火紅的嫁衣襯著肌膚如雪社痛。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,215評論 1 299
  • 那天命雀,我揣著相機(jī)與錄音蒜哀,去河邊找鬼。 笑死吏砂,一個胖子當(dāng)著我的面吹牛撵儿,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播狐血,決...
    沈念sama閱讀 40,096評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼淀歇,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了匈织?” 一聲冷哼從身側(cè)響起浪默,我...
    開封第一講書人閱讀 38,939評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎缀匕,沒想到半個月后纳决,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,354評論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡乡小,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,573評論 2 333
  • 正文 我和宋清朗相戀三年阔加,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片满钟。...
    茶點(diǎn)故事閱讀 39,745評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡胜榔,死狀恐怖胳喷,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情苗分,我是刑警寧澤厌蔽,帶...
    沈念sama閱讀 35,448評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站摔癣,受9級特大地震影響奴饮,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜择浊,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,048評論 3 327
  • 文/蒙蒙 一戴卜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧琢岩,春花似錦投剥、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至糕篇,卻和暖如春啄育,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背拌消。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評論 1 269
  • 我被黑心中介騙來泰國打工挑豌, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人墩崩。 一個月前我還...
    沈念sama閱讀 47,776評論 2 369
  • 正文 我出身青樓氓英,卻偏偏與公主長得像,于是被迫代替她去往敵國和親鹦筹。 傳聞我的和親對象是個殘疾皇子铝阐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,652評論 2 354

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