1.函數(shù)的聲明定義
兩種方式:
函數(shù)聲明語句
function foo1(args){
var x = 'hello';
}
函數(shù)表達(dá)式
var foo2 = function(args){ var x = 'hello' };
兩種的區(qū)別:
第一種办绝,函數(shù)的定義會(huì)在執(zhí)行上下文開始執(zhí)行代碼之前被提升积蜻,通俗的講院崇,就是在函數(shù)聲明語句之前就可以調(diào)用函數(shù)了摔寨。
第二種迈着,在執(zhí)行上下文開始執(zhí)行代碼之前嬉橙,只有變量foo2會(huì)被提升,變量的初始化還在原來代碼的位置寥假,所以在函數(shù)表達(dá)式之前,foo2的值為undefined霞扬。
函數(shù)聲明和定義可以嵌套到其他函數(shù)里
2.函數(shù)調(diào)用
函數(shù)聲明的調(diào)用foo1() //這種是作為函數(shù)調(diào)用
作為方法屬性調(diào)用 obj.foo() //這種是作為方法調(diào)用
構(gòu)造函數(shù)調(diào)用 new Foo() //用于新建對(duì)象
三種的區(qū)別:
以函數(shù)調(diào)用形式調(diào)用的函數(shù)其this的值為全局對(duì)象(非嚴(yán)格)或者undefined(嚴(yán)格模式)糕韧,不管這個(gè)函數(shù)聲明在其他函數(shù)里還是在其他地方
以方法形式調(diào)用的函數(shù)其this的值為調(diào)用它的對(duì)象
function foo1(){
console.log(this);
foo2();
function foo2(){
console.log(this)
}
}
var obj ={name : "obj", foo : foo1};
obj.foo(); //結(jié)果輸出為{name: "obj", foo: ?} 和window
//直接在瀏覽器的控制臺(tái)粘貼這段代碼看結(jié)果
將foo2的函數(shù)聲明變?yōu)楹瘮?shù)表達(dá)式再試試
function foo1(){
console.log(this);
var foo2 = function (){
console.log(this)
}
foo2(); //這里輸出的this為什么為window??????
}
var obj ={name : "obj", foo : foo1};
obj.foo();
//對(duì)于foo2為什么輸出的是window我也很疑惑,函數(shù)表達(dá)式調(diào)用其實(shí)是看作方法調(diào)用的喻圃,
//所以foo2里的this應(yīng)該是調(diào)用它的作用域的變量對(duì)象萤彩,很疑惑
構(gòu)造函數(shù)調(diào)用
構(gòu)造函數(shù)調(diào)用創(chuàng)建一個(gè)新的空對(duì)象,這個(gè)對(duì)象繼承自構(gòu)造函數(shù)的prototype屬性斧拍,構(gòu)造函數(shù)可以初始化這個(gè)新的對(duì)象雀扶,并將這個(gè)對(duì)象作為其的調(diào)用上下文(this),可以用this引用新創(chuàng)建的對(duì)象肆汹。如 new o.m();中愚墓,m調(diào)用的上下文不是o。//一般不這么用
構(gòu)造函數(shù)一般沒有返回值昂勉,不過如果顯式地返回一 個(gè)對(duì)象浪册,則這個(gè)調(diào)用表達(dá)式的值就是這個(gè)對(duì)象 // 一般不這么用
3.函數(shù)的作用域(鏈)
函數(shù)的作用域鏈在函數(shù)聲明定義的時(shí)候就已確定了(這里很難講清楚,應(yīng)該說是在聲明定義時(shí)確定了一條作用域鏈岗照,這個(gè)作用域鏈不包括函數(shù)本身的作用域村象,只有在函數(shù)被調(diào)用時(shí),函數(shù)本身的作用域才加入到其作用域鏈頂部)攒至。
不管函數(shù)在哪里被調(diào)用厚者,它的作用域鏈在定義時(shí)就被確定了,作用域鏈只和函數(shù)被定義的地方有關(guān)迫吐。
對(duì)于作為對(duì)象方法的函數(shù)的作用域:
var obj = {name : 'obj' ,
foo : function(args){ console.log(name)} ,
callfoo : function(){ obj.foo();}
};
var name = 'scope';
function outterFoo(){ console.log(name)};
obj.foo();
outterFoo();
obj.callfoo();
//輸出的結(jié)果都為scope
作為對(duì)象方法的函數(shù)的作用域鏈(未被調(diào)用前)和與對(duì)象在同一層的函數(shù)的作用域鏈?zhǔn)且粯拥摹?/p>
4.函數(shù)的執(zhí)行上下文
在打開頁面時(shí)库菲,全局執(zhí)行上下文就被壓入執(zhí)行上下文棧中,當(dāng)調(diào)用函數(shù)時(shí)會(huì)將向執(zhí)行上下文中壓入函數(shù)的執(zhí)行上下文渠抹,在函數(shù)中如果調(diào)用其它函數(shù)則繼續(xù)壓入新的執(zhí)行上下文蝙昙,函數(shù)執(zhí)行完之后闪萄,其執(zhí)行上下文被彈出棧。
之后會(huì)寫文章從內(nèi)存的角度來分析函數(shù)的執(zhí)行上下文奇颠。持續(xù)關(guān)注
5.函數(shù)里變量的查找
函數(shù)里變量的查找是在作用域鏈上依次查找的败去,會(huì)一層一層向外查找。變量的查找不同于this的屬性的查找
this和作用域是兩個(gè)完全不同的概念 this是javascript的關(guān)鍵字而不是變量烈拒。
6.函數(shù)的this
this也可以叫做調(diào)用上下文(和執(zhí)行上下文有區(qū)別) // 個(gè)人見解
在不指定的情況下圆裕,this指向的是調(diào)用該方法的對(duì)象。
this上屬性的查找是在對(duì)象的原型鏈上查找的
在構(gòu)造函數(shù)中荆几,this指向的是通過new關(guān)鍵字新建的實(shí)例對(duì)象
可以指定this屬性的指向
利用call apply bind 三個(gè)函數(shù)
function foo(arg1,arg2,arg3){};
foo.call{obj,arg1,arg2...} //call指定this為obj吓妆,后面的參數(shù)作為foo的參數(shù)傳進(jìn)去
foo.apply{obj,[arg1,arg2]} //也是制定this為obj,但是傳給foo的參數(shù)是以數(shù)組的形式
var newfoo = foo.bind(obj,arg1,arg2) // 為foo綁定this吨铸,和兩個(gè)參數(shù) bind返回的是一個(gè)新函數(shù)
調(diào)用新的函數(shù)行拢,會(huì)調(diào)用foo,而且foo的this都是指向obj诞吱,而且傳入newfoo的參數(shù)都作為參數(shù)賦值給arg3及后面的參數(shù)舟奠,因?yàn)閍rg1,arg2已經(jīng)被綁定了。
//模擬bind , bind的一些特性還是模擬不來房维,功能可以模擬
Function.prototype.bind = Function.prototype.bind || function(obj...){
var self = this;
var boundArgs = arguments;
return function(){
var args=[],i;
for(i=1;i<boundArgs.length;i++) args.push(boundArgs[i]);
for(i=0;i<arguments.length;i++) args.push(arguments[i]);
return self.apply(obj,args);
}
};
7.自定義函數(shù)屬性
函數(shù)也是一種特殊的對(duì)象沼瘫,可以為其自定義屬性。
function foo(){console.log(foo.counter++)};
foo.counter = 0;
這種做法有個(gè)問題咙俩,函數(shù)的counter屬性可以被隨性修改耿戚,可以利用閉包將屬性私有化。
通過給構(gòu)造函數(shù)添加方法和屬性就模擬實(shí)現(xiàn)了類方法和類字段
8.閉包
一句話理解閉包阿趁,局部作用域的變量被外部引用時(shí)膜蛔,其內(nèi)存空間不會(huì)被銷毀 (本人愚見,歡迎各路大神指正)
var unique = (function(){
var counter = 0;
return function(){ return counter++}}()); //閉包的典型例子
//函數(shù)每次調(diào)用時(shí)在內(nèi)存中創(chuàng)建的空間是不一樣的歌焦。
function getUniqueFoo(){
var counter = 0;
return function(){ return counter++} //這里返回的函數(shù)里存在外層函數(shù)的局部變量counter
}
var unique2 = getUniqueFoo(); //unique2指向返回的函數(shù)
var unique3 = geUniqueFoo(); //unique2和unique3是互不干擾的飞几,因?yàn)閮?nèi)存空間不是同一塊
//又一個(gè)閉包例子
function getApp(){
var appName = "xxx";
var version = "1.xxx";
var setName = function(name){
appName = name;
}
return {
get app(){ return appName}, //存取器屬性
version : version,
setName : setName,
}
}
var App =getApp();
可以在外部函數(shù)將this轉(zhuǎn)存為一個(gè)變量,以便在閉包中訪問,外部函數(shù)的arguments 也一樣
arguments是函數(shù)的類數(shù)組對(duì)象
arguments.callee 指向的是arguments所在的函數(shù)本身
之后會(huì)寫文章從內(nèi)存的角度來分析函數(shù)的閉包独撇。持續(xù)關(guān)注