亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

詳解JavaScript的閉包、IIFE、apply、函數(shù)與對(duì)象

 更新時(shí)間:2016年12月21日 10:22:25   作者:張果  
本文主要對(duì)JavaScript的閉包、IIFE、apply、函數(shù)與對(duì)象進(jìn)行詳細(xì)介紹。有很好的參考價(jià)值,需要的朋友一起來(lái)看下吧

目錄

一、閉包(Closure)

1.1、閉包相關(guān)的問(wèn)題

1.2、理解閉包

二、對(duì)象

2.1、對(duì)象常量(字面量)

2.2、取值

2.3、枚舉(遍歷)

2.4、更新與添加

2.5、對(duì)象的原型

2.6、刪除

2.7、封裝

三、函數(shù)

3.1、參數(shù)對(duì)象 (arguments)

3.2、構(gòu)造函數(shù)

3.3、函數(shù)調(diào)用

3.3.1、call

3.3.2、apply

3.3.3、caller

3.3.4、Callee

3.5、立即執(zhí)行函數(shù)表達(dá)式 (IIFE)

3.5.1、匿名函數(shù)與匿名對(duì)象

3.5.2、函數(shù)與函數(shù)表達(dá)式

3.5.3、立即執(zhí)行函數(shù)表達(dá)式與匿名對(duì)象

3.5.4、各種IIFE的寫(xiě)法

3.5.5、參數(shù)

3.5.6、添加分號(hào)

3.5.7、IIFE的作用

3.5.8、IIFE的變形

四、示例下載

一、閉包(Closure)

1.1、閉包相關(guān)的問(wèn)題

請(qǐng)?jiān)陧?yè)面中放10個(gè)div,每個(gè)div中放入字母a-j,當(dāng)點(diǎn)擊每一個(gè)div時(shí)顯示索引號(hào),如第1個(gè)div顯示0,第10個(gè)顯示9;方法:找到所有的div,for循環(huán)綁定事件。

示例代碼:

<!DOCTYPE html>
<html>
 <head>
 <meta charset="UTF-8">
 <title>閉包</title>
 <style type="text/css">
 div {
 width: 100px;
 height: 100px;
 background: lightgreen;
 float: left;
 margin: 20px;
 font: 30px/100px "microsoft yahei";
 text-align: center;
 }
 </style>
 </head>
 <body>
 <div>a</div>
 <div>b</div>
 <div>c</div>
 <div>d</div>
 <div>e</div>
 <div>f</div>
 <div>g</div>
 <div>h</div>
 <div>i</div>
 <div>j</div>
 <script type="text/javascript">
 var divs=document.getElementsByTagName("div");
 for (var i=0;i<divs.length;i++) {
 divs[i].onclick=function(){
 alert(i);
 }
 }
 </script>
 </body>
</html>

運(yùn)行結(jié)果:

因?yàn)辄c(diǎn)擊事件的函數(shù)內(nèi)部使用外部的變量i一直在變化,當(dāng)我們指定click事件時(shí)并沒(méi)有保存i的副本,這樣做也是為了提高性能,但達(dá)不到我們的目的,我們要讓他執(zhí)行的上下文保存i的副本,這種機(jī)制就是閉包。

修改后的代碼:

<!DOCTYPE html>
<html>
 <head>
 <meta charset="UTF-8">
 <title>閉包</title>
 <style type="text/css">
 div {
 width: 100px;
 height: 100px;
 background: lightgreen;
 float: left;
 margin: 20px;
 font: 30px/100px "microsoft yahei";
 text-align: center;
 }
 </style>
 </head>
 <body>
 <div>a</div>
 <div>b</div>
 <div>c</div>
 <div>d</div>
 <div>e</div>
 <div>f</div>
 <div>g</div>
 <div>h</div>
 <div>i</div>
 <div>j</div>
 <script type="text/javascript">
 var divs=document.getElementsByTagName("div");
 for (var i=0;i<divs.length;i++) {
 divs[i].onclick=(function(n){
 return function(){
 alert(n); 
 }
 })(i);
 }
 </script>
 </body>
</html>

運(yùn)行結(jié)果:

n是外部函數(shù)的值,但是內(nèi)部函數(shù)(點(diǎn)擊事件)需要使用,返回函數(shù)前的n被臨時(shí)駐留在內(nèi)存中給點(diǎn)擊事件使用,簡(jiǎn)單說(shuō)就是函數(shù)的執(zhí)行上下文被保存起來(lái),i生成了多個(gè)副本。

1.2、理解閉包

閉包概念:當(dāng)一個(gè)內(nèi)部函數(shù)被調(diào)用,就會(huì)形成閉包,閉包就是能夠讀取其他函數(shù)內(nèi)部變量的函數(shù),定義在一個(gè)函數(shù)內(nèi)部的函,創(chuàng)建一個(gè)閉包環(huán)境,讓返回的這個(gè)子程序抓住i,以便在后續(xù)執(zhí)行時(shí)可以保持對(duì)這個(gè)i的引用。內(nèi)部函數(shù)比外部函數(shù)有更長(zhǎng)的生命周期;函數(shù)可以訪問(wèn)它被創(chuàng)建時(shí)所處的上下文環(huán)境。

Javascript語(yǔ)言特有的"鏈?zhǔn)阶饔糜?結(jié)構(gòu)(chain scope),子對(duì)象會(huì)一級(jí)一級(jí)地向上尋找所有父對(duì)象的變量

二、對(duì)象

對(duì)象就是“鍵/值”對(duì)的集合并擁有一個(gè)連接到原型(prototype)對(duì)隱藏連接。

2.1、對(duì)象常量(字面量)

一個(gè)對(duì)象字面量就是包含在一對(duì)花括號(hào)中的零個(gè)或多個(gè)“鍵/值”對(duì)。對(duì)象字面量可以出現(xiàn)在任何允許表達(dá)式出現(xiàn)的地方。

對(duì)象的定義:

//空對(duì)象
 var obj1={};
 //對(duì)象中的屬性
 var obj2={name:"foo",age:19};
 var obj3={"nick name":"dog"};
 //對(duì)象中的方法
 var obj4={
 price:99,
 inc:function(){
 this.price+=1;
 }
 }

對(duì)象中可包含的內(nèi)容:

對(duì)象常量可以出現(xiàn)在任何允許表達(dá)式出現(xiàn)的地方,對(duì)象、數(shù)組、函數(shù)可以相互間嵌套,形式可以多種多樣。對(duì)象的值可以是:數(shù)組,函數(shù),對(duì)象,基本數(shù)據(jù)類(lèi)型等。

//對(duì)象中可包含的內(nèi)容
 var obj5 = [{
 name: "jack"
 }, {
 name: "lucy", //常量
 hobby:["讀書(shū)","上網(wǎng)","代碼"], //數(shù)組
 friend:{name:"mark",height:198,friend:{}}, //對(duì)象
 show:function(){ //函數(shù)
 console.log("大家好,我是"+this.name);
 }
 }];
 //對(duì)象中的this是動(dòng)態(tài)的,指向的是:調(diào)用者
 obj5[1].show();

輸出:大家好,我是lucy

2.2、取值

方法一:直接使用點(diǎn)號(hào)運(yùn)算

 //3取值
 var obj6={"nick name":"pig",realname:"Rose"};
 console.log(obj6.realname);
 //console.log(obj6.nick name); 錯(cuò)誤

方法二:使用索引器,當(dāng)對(duì)象中的key有空格是

 //3取值
 var obj6={"nick name":"pig",realname:"Rose"};
 console.log(obj6["realname"]);
 console.log(obj6["nick name"]);

2.3、枚舉(遍歷)

方法一:

var obj7={weight:"55Kg","nick name":"pig",realname:"Rose"};
 for (var key in obj7) {
 console.log(key+":"+obj7[key]);
 }

運(yùn)行結(jié)果:

輸出順序是不能保證的。

2.4、更新與添加

如果對(duì)象中存在屬性就修改對(duì)應(yīng)值,如果不存在就添加。對(duì)象通過(guò)引用傳遞,它們永遠(yuǎn)不會(huì)被復(fù)制

var obj8={realname:"King"};
 obj8.realname="Queen"; //修改
 obj8.weight=1000; //添加屬性
 obj8.show=function() //添加方法
 {
 console.log(this.realname+","+this.weight);
 }
 obj8.show();

輸出:

Queen,1000

var obj8={realname:"King"};
 obj8.realname="Queen"; //修改
 obj8.weight=1000; //添加屬性
 obj8.show=function() //添加方法
 {
 console.log(this.realname+","+this.weight);
 }
 obj8.show();
 
 //引用
 var obj9=obj8; //obj9指向obj8的引用
 obj9.realname="Jack";
 obj8.show();

輸出:

2.5、對(duì)象的原型

javascript是一種動(dòng)態(tài)語(yǔ)言,與C#和Java這樣的靜態(tài)語(yǔ)言是不一樣的;javascript并沒(méi)有嚴(yán)格的類(lèi)型,可以簡(jiǎn)單認(rèn)為javascript是由對(duì)象組成的,對(duì)象間連接到原型(prototype)實(shí)現(xiàn)功能的擴(kuò)展與繼承。每個(gè)對(duì)象都鏈接到一個(gè)原型對(duì)象,并且可以從中繼承屬性,所有通過(guò)常量(字面量)創(chuàng)建的對(duì)象都連接到Object.prototype,它是JavaScript中的頂級(jí)(標(biāo)配)對(duì)象,類(lèi)似高級(jí)語(yǔ)言中的根類(lèi)。

現(xiàn)在我們修改系統(tǒng)中的Object對(duì)象,添加一個(gè)創(chuàng)建方法,指定要?jiǎng)?chuàng)建對(duì)象的原型,實(shí)現(xiàn)類(lèi)似繼承功能:

<script type="text/javascript">
 if(typeof Object.beget !== "function")
 {
 Object.create = function(o) {
 //構(gòu)造函數(shù),用于創(chuàng)建對(duì)象
 var F = function() {};
 //指定由構(gòu)造函數(shù)創(chuàng)建的對(duì)象的原型
 F.prototype = o;
 //調(diào)用構(gòu)造方法創(chuàng)建新對(duì)象
 return new F();
 }
 }
 var rose={
 name:"rose",
 show:function(){
 console.log("姓名:"+this.name);
 }
 };
 rose.show(); //輸出
 var lucy=Object.create(rose); //簡(jiǎn)單認(rèn)為是:創(chuàng)建一個(gè)對(duì)象且繼承rose
 lucy.name="lucy"; //重寫(xiě)
 lucy.show();
 </script>

運(yùn)行結(jié)果:

原型關(guān)系是一種動(dòng)態(tài)關(guān)系,如果修改原型,該原型創(chuàng)建的對(duì)象會(huì)受到影響。

var lucy=Object.create(rose); //簡(jiǎn)單認(rèn)為是:創(chuàng)建一個(gè)對(duì)象且繼承rose
 lucy.name="lucy"; //重寫(xiě)
 
 var jack=Object.create(rose);
 jack.name="jack";
 
 //修改原型中的方法
 rose.show=function(){
 console.log("姓名->"+this.name);
 }
 
 lucy.show();
 jack.show();

結(jié)果:

關(guān)于原型在函數(shù)中會(huì)再講到。

2.6、刪除

 //刪除屬性
 delete mark.name; 
 //調(diào)用方法,輸出:姓名:undefined
 mark.show(); 
 //刪除函數(shù)
 delete mark.show; 
 //錯(cuò)誤,mark.show is not a function
 mark.show();

刪除不用的屬性是一個(gè)好習(xí)慣,在某些情況下可能引發(fā)內(nèi)存泄漏。

2.7、封裝

使用對(duì)象封裝的好處是可以減少全局變量的污染機(jī)會(huì),將屬性,函數(shù)都隸屬一個(gè)對(duì)象。

封裝前:

var name="foo"; //name是全局的,被暴露
 i=1; //全局的,沒(méi)有var關(guān)鍵字聲明的變量是全局的,與位置關(guān)系不大
 function show(){ //show 是全局的,被暴露
 console.log("name->"+name);
 console.log(++i);
 }
 //i是全局的 2
 show(); 
 //3
 show();

封裝后:

//對(duì)外只暴露bar,使用閉包封裝
 var bar=function(){
 var i=1;
 return{
 name:"bar",
 show:function(){
 console.log("name->"+this.name);
 console.log(++i);
 }
 };
 }; 
 var bar1=bar();
 //2
 bar1.show();
 //3
 bar1.show(); 
 var bar2=bar();
 //2,因?yàn)楸环庋b,且閉包,i是局部私有的
 bar2.show();

運(yùn)行結(jié)果:

三、函數(shù)

javascript中的函數(shù)就是對(duì)象,對(duì)象就是“鍵/值”對(duì)的集合并擁有一個(gè)連接到原型對(duì)隱藏連接。

3.1、參數(shù)對(duì)象 (arguments)

第一個(gè)函數(shù)中有一個(gè)默認(rèn)對(duì)象叫arguments,類(lèi)似數(shù)組,但不是數(shù)組,該對(duì)象是傳遞給函數(shù)的參數(shù)。

<script type="text/javascript">
 function counter(){
 var sum=0;
 for(var i=0;i<arguments.length;i++){
 sum+=arguments[i];
 }
 return sum;
 }
 console.log(counter(199,991,1,2,3,4,5));
 console.log(counter());
 </script>

運(yùn)行結(jié)果:

1205

0

這里的arguments是一個(gè)隱式對(duì)象,不聲明也在函數(shù)中,內(nèi)部函數(shù)可以訪問(wèn)外部函數(shù)的任意內(nèi)容,但是不能直接訪問(wèn)外部函數(shù)的arguments與this對(duì)象。

function f1()
 {
 console.log(arguments.length);
 f2=function()
 {
 console.log(arguments.length);
 }
 return f2;
 }
 var f=f1(1,2,3);
 f();

運(yùn)行結(jié)果:

3

0

3.2、構(gòu)造函數(shù)

在javascript中對(duì)象構(gòu)造函數(shù)可以創(chuàng)建一個(gè)對(duì)象。

<script type="text/javascript">
 /*構(gòu)造函數(shù)*/
 //可以簡(jiǎn)單的認(rèn)為是一個(gè)類(lèi)型的定義
 function Student(name,age){
 this.name=name;
 this.age=age;
 this.show=function(){
 console.log(this.name+","+this.age);
 }
 }
 //通過(guò)new關(guān)鍵字調(diào)用構(gòu)造函數(shù),創(chuàng)建一個(gè)對(duì)象tom
 var rose=new Student("rose",18);
 var jack=new Student("jack",20);
 
 rose.show();
 jack.show();
 </script>

3.3、函數(shù)調(diào)用

3.3.1、call

調(diào)用一個(gè)對(duì)象的一個(gè)方法,以另一個(gè)對(duì)象替換當(dāng)前對(duì)象

call([thisObj[,args])

hisObj 可選項(xiàng)。將被用作當(dāng)前對(duì)象的對(duì)象。args 將被傳遞方法參數(shù)序列。

call 方法可以用來(lái)代替另一個(gè)對(duì)象調(diào)用一個(gè)方法。call 方法可將一個(gè)函數(shù)的對(duì)象上下文從初始的上下文改變?yōu)橛?thisObj 指定的新對(duì)象。

示例:

/*構(gòu)造函數(shù)*/
 function Student(name,age){
 this.name=name;
 this.age=age;
 }
 show=function(add){
 console.log(add+":"+this.name+","+this.age);
 }
 //通過(guò)new關(guān)鍵字調(diào)用構(gòu)造函數(shù),創(chuàng)建一個(gè)對(duì)象tom
 var rose=new Student("rose",18);
 var jack=new Student("jack",20);
 //調(diào)用show方法,指定上下文,指定調(diào)用對(duì)象,this指向rose,“大家好是參數(shù)”
 show.call(rose,"大家好");
 show.call(jack,"Hello");

運(yùn)行結(jié)果:

call方法中的參數(shù)都可以省去,第1個(gè)參數(shù)表示在哪個(gè)對(duì)象上調(diào)用該方法,或this指向誰(shuí),如果不指定則會(huì)指向window對(duì)象。

示例:

 var name="無(wú)名";
 var age=18;
 show.call();

結(jié)果:

undefined:無(wú)名,18

3.3.2、apply

apply([thisObj[,argArray]])

應(yīng)用某一對(duì)象的一個(gè)方法,用另一個(gè)對(duì)象替換當(dāng)前對(duì)象,與call類(lèi)似。

如果 argArray 不是一個(gè)有效的數(shù)組或者不是arguments對(duì)象,那么將導(dǎo)致一個(gè) TypeError。

如果沒(méi)有提供 argArray 和 thisObj 任何一個(gè)參數(shù),那么 Global 對(duì)象將被用作 thisObj, 并且無(wú)法被傳遞任何參數(shù)。

對(duì)于第一個(gè)參數(shù)意義都一樣,但對(duì)第二個(gè)參數(shù):

apply傳入的是一個(gè)參數(shù)數(shù)組,也就是將多個(gè)參數(shù)組合成為一個(gè)數(shù)組傳入,而call則作為call的參數(shù)傳入(從第二個(gè)參數(shù)開(kāi)始)。

如 func.call(func1,var1,var2,var3)對(duì)應(yīng)的apply寫(xiě)法為:func.apply(func1,[var1,var2,var3])

同時(shí)使用apply的好處是可以直接將當(dāng)前函數(shù)的arguments對(duì)象作為apply的第二個(gè)參數(shù)傳入

示例代碼:

/*構(gòu)造函數(shù)*/
 function Student(name,age){
 this.name=name;
 this.age=age;
 }
 show=function(greeting,height){
 console.log(greeting+":"+this.name+","+this.age+","+height);
 }
 //通過(guò)new關(guān)鍵字調(diào)用構(gòu)造函數(shù),創(chuàng)建一個(gè)對(duì)象tom
 var rose=new Student("rose",18);
 var jack=new Student("jack",20);
 //調(diào)用show方法,指定上下文,指定調(diào)用對(duì)象,this指向rose,“大家好是參數(shù)”
 show.apply(rose,["大家好","178cm"]);
 show.apply(jack,["Hello","188cm"]);

運(yùn)行結(jié)果:

從上面的示例中可以發(fā)現(xiàn)apply的第2個(gè)參數(shù)是一個(gè)數(shù)組,數(shù)組中的內(nèi)容將映射到被調(diào)用方法的參數(shù)中,如果單這樣看發(fā)現(xiàn)不如call方便,其實(shí)如果直接取方法的參數(shù)arguments則apply要方便一些。通過(guò)簡(jiǎn)單的變化就可以替代call。

 function display(){
 show.apply(jack,arguments);
 }
 display("hi","224cm");

結(jié)果:

hi:jack,20,224cm

javascript里call和apply操作符可以隨意改變this指向

如果在javascript語(yǔ)言里沒(méi)有通過(guò)new(包括對(duì)象字面量定義)、call和apply改變函數(shù)的this指針,函數(shù)的this指針都是指向window的。

關(guān)于this指針,我的總結(jié)是:是誰(shuí)調(diào)用的函數(shù),那么這個(gè)函數(shù)中的this指針就是它;如果沒(méi)有明確看出是誰(shuí)調(diào)用的,那么應(yīng)該就是window調(diào)用的,那么this指針就是window。

3.3.3、caller

在一個(gè)函數(shù)調(diào)用另一個(gè)函數(shù)時(shí),被調(diào)用函數(shù)會(huì)自動(dòng)生成一個(gè)caller屬性,指向調(diào)用它的函數(shù)對(duì)象。如果該函數(shù)當(dāng)前未被調(diào)用,或并非被其他函數(shù)調(diào)用,則caller為null。

在JavaScript的早期版本中,F(xiàn)unction對(duì)象的caller屬性是對(duì)調(diào)用當(dāng)前函數(shù)的函數(shù)的引用

function add()
 {
 console.log("add被調(diào)用");
 //add方法的調(diào)用函數(shù),如果調(diào)用add方法的不是函數(shù)則為null
 console.log(add.caller);
 }
 function calc(){
 add();
 }
 //直接調(diào)用add方法
 add(); 
 //間接通過(guò)calc方法調(diào)用
 calc();

運(yùn)行結(jié)果:

caller與this還是有區(qū)別的,this是指調(diào)用方法的對(duì)象,而caller是指調(diào)用函數(shù)的函數(shù)。

<script type="text/javascript">
 function add(n)
 {
 console.log("add被調(diào)用");
 if(n<=2){
 return 1;
 }
 return add.caller(n-1)+add.caller(n-2);
 }
 function calc(n){
 console.log("calc被調(diào)用");
 return add(n);
 }
 //1 1 2
 console.log(calc(3));
 </script>

結(jié)果:

3.3.4、Callee

當(dāng)函數(shù)被調(diào)用時(shí),它的arguments.callee對(duì)象就會(huì)指向自身,也就是一個(gè)對(duì)自己的引用

function add(n1,n2){
 console.log(n1+n2);
 //arguments.callee(n1,n2); //指向add方法
 return arguments.callee;
 }
 add(1,2)(3,4)(5,6)(7,8)(8,9);

運(yùn)行結(jié)果:

當(dāng)?shù)?次調(diào)用add方法時(shí)輸入3,立即將函數(shù)返回再次調(diào)用,每次調(diào)用后又返回自己,這樣可以實(shí)現(xiàn)鏈?zhǔn)骄幊獭?/p>

3.5、立即執(zhí)行函數(shù)表達(dá)式 (IIFE)

IIFE即Immediately-Invoked Function Expression,立即執(zhí)行函數(shù)表達(dá)式

3.5.1、匿名函數(shù)與匿名對(duì)象

匿名函數(shù)就是沒(méi)有名稱(chēng)的函數(shù),javascript中經(jīng)常會(huì)使用匿名函數(shù)實(shí)現(xiàn)事件綁定,回調(diào),實(shí)現(xiàn)函數(shù)級(jí)的私有作用域,如下所示:

 function(){
 console.log("這是一個(gè)匿名函數(shù)");
 };

匿名對(duì)象:

 {
 name:"foo",
 show:function(){
 console.log(this.name);
 }
 }

沒(méi)有名稱(chēng)的匿名函數(shù)也叫函數(shù)表達(dá)式,它們間是有區(qū)別的。

3.5.2、函數(shù)與函數(shù)表達(dá)式

下面是關(guān)于函數(shù)與函數(shù)表達(dá)式定義時(shí)的區(qū)別

a)、函數(shù)定義(Function Declaration)

function Identifier ( Parameters ){ FunctionBody }

function 函數(shù)名稱(chēng)(參數(shù)){函數(shù)主體}

在函數(shù)定義中,參數(shù)(Parameters)標(biāo)識(shí)符(Identifier )是必不可少的。如果遺漏,會(huì)報(bào)提示錯(cuò)誤:

代碼:

 function(){
 console.log("這是一個(gè)匿名函數(shù)");
 };

結(jié)果:

b)、函數(shù)表達(dá)式(Function Expression)

function Identifier(Parameters){ FunctionBody }

函數(shù)表達(dá)式中,參數(shù)和標(biāo)識(shí)符都是可選的,與函數(shù)定義的區(qū)別是標(biāo)識(shí)符可省去。

其實(shí),"function Identifier(Parameters){ FunctionBody }"并不是一個(gè)完整的函數(shù)表達(dá)式,完整的函數(shù)的表達(dá)式,需要一個(gè)賦值操作。

比如: var name=function Identifier(Parameters){ FunctionBody }

3.5.3、立即執(zhí)行函數(shù)表達(dá)式與匿名對(duì)象

 //1 正常定義函數(shù)
 function f1(){
 console.log("正常定義f1函數(shù)");
 };
 //2 被誤解的函數(shù)表達(dá)式
 function(){
 console.log("報(bào)錯(cuò)Unexpected token (");
 }();
 //3 IIFE,括號(hào)中的內(nèi)容被解釋成函數(shù)表達(dá)式
 (function(){
 console.log("IIFE,正常執(zhí)行");
 })();
 //4 函數(shù)表達(dá)式
 var f2=function(){
 console.log("這也被視為函數(shù)表達(dá)式");
 };

第3種寫(xiě)法為什么這樣就能立即執(zhí)行并且不報(bào)錯(cuò)呢?因?yàn)樵趈avascript里,括號(hào)內(nèi)部不能包含語(yǔ)句,當(dāng)解析器對(duì)代碼進(jìn)行解釋的時(shí)候,先碰到了(),然后碰到function關(guān)鍵字就會(huì)自動(dòng)將()里面的代碼識(shí)別為函數(shù)表達(dá)式而不是函數(shù)聲明。

如果需要將函數(shù)表達(dá)式或匿名對(duì)象立即執(zhí)行,可以使用如下方法:

<!DOCTYPE html>
<html>
 <head>
 <meta charset="UTF-8">
 <title>IIFE</title>
 </head>
 <body>
 <script type="text/javascript">
 //調(diào)用匿名函數(shù)
 (function() {
 console.log("這是一個(gè)函數(shù)表達(dá)式");
 })();
 //調(diào)用匿名對(duì)象
 ({
 name: "foo",
 show: function() {
 console.log(this.name);
 }
 }).show();
 console.log({
 a: 1
 }.a);
 console.log({
 a: function() {}
 }.a());
 </script>
 </body>
</html>

運(yùn)行結(jié)果:

3.5.4、各種IIFE的寫(xiě)法

//最常用的兩種寫(xiě)法
(function(){ /* code */ }()); // 老師推薦寫(xiě)法
(function(){ /* code */ })(); // 當(dāng)然這種也可以
// 括號(hào)和JS的一些操作符(如 = && || ,等)可以在函數(shù)表達(dá)式和函數(shù)聲明上消除歧義
// 如下代碼中,解析器已經(jīng)知道一個(gè)是表達(dá)式了,于是也會(huì)把另一個(gè)默認(rèn)為表達(dá)式
// 但是兩者交換則會(huì)報(bào)錯(cuò)
var i = function(){ return 10; }();
true && function(){ /* code */ }();
0, function(){ /* code */ }();
// 如果你不怕代碼晦澀難讀,也可以選擇一元運(yùn)算符
!function(){ /* code */ }();
~function(){ /* code */ }();
-function(){ /* code */ }();
+function(){ /* code */ }();
// 你也可以這樣
new function(){ /* code */ }
new function(){ /* code */ }() // 帶參

如果是函數(shù)表達(dá)式,可直接在其后加"()"立即執(zhí)行。

如果是函數(shù)聲明,可以通過(guò)"()"、"+"、"-"、"void"、"new"等運(yùn)算符將其轉(zhuǎn)換為函數(shù)表達(dá)式,然后再加"()"立即執(zhí)行。

3.5.5、參數(shù)

函數(shù)表達(dá)式也是函數(shù)的一種表達(dá)形式,同樣可以像函數(shù)一樣使用參數(shù),如下所示:

 (function (n){
 console.log(n);
 })(100);

輸出:100

其實(shí)通過(guò)IIFE還能形成一個(gè)類(lèi)似的塊級(jí)作用域,當(dāng)塊內(nèi)的程序在使用外部對(duì)象時(shí)將優(yōu)先查找塊內(nèi)的對(duì)象,再查找塊外的對(duì)象,依次向上。

 (function(win,undfd){
 win.console.log("Hello"==undfd);
 })(window,undefined);

3.5.6、添加分號(hào)

為了避免與其它的javascript代碼產(chǎn)生影響后報(bào)錯(cuò),常常會(huì)在IIFE前增加一個(gè)分號(hào),表示前面所有的語(yǔ)句都結(jié)束了,開(kāi)始新的一語(yǔ)句。

 var k=100
 (function (n){
 console.log(n);
 })(k);

上面的腳本會(huì)報(bào)錯(cuò),因?yàn)閖avascript解釋器會(huì)認(rèn)為100是函數(shù)名。

 var k=100
 ;(function (n){
 console.log(n);
 })(k);

這樣就正確了,在javascript中一行語(yǔ)句的結(jié)束可以使用分號(hào),也可以不使用分號(hào),因?yàn)橐话愕淖远x插件會(huì)使用IIFE,這是一段獨(dú)立的代碼,在應(yīng)用過(guò)程中不能保證用戶(hù)會(huì)加上分號(hào),所以建議在IIFE前加上分號(hào)。

3.5.7、IIFE的作用

1)、提高性能

減少作用域查找時(shí)間。使用IIFE的一個(gè)微小的性能優(yōu)勢(shì)是通過(guò)匿名函數(shù)的參數(shù)傳遞常用全局對(duì)象window、document、jQuery,在作用域內(nèi)引用這些全局對(duì)象。JavaScript解釋器首先在作用域內(nèi)查找屬性,然后一直沿著鏈向上查找,直到全局范圍。將全局對(duì)象放在IIFE作用域內(nèi)提升js解釋器的查找速度和性能。

function(window, document, $) {
}(window, document, window.jQuery);

2)、壓縮空間

通過(guò)參數(shù)傳遞全局對(duì)象,壓縮時(shí)可以將這些全局對(duì)象匿名為一個(gè)更加精簡(jiǎn)的變量名

function(w, d, $) { 
}(window, document, window.jQuery);

3)、避免沖突

 匿名函數(shù)內(nèi)部可以形成一個(gè)塊級(jí)的私有作用域。

4)、依賴(lài)加載

可以靈活的加載第三方插件,當(dāng)然使用模塊化加載更好(AMD,CMD),示例如下。

A.html與B.html文件同時(shí)引用公用的common.js文件,但是只有A.html需要使用到StuObj對(duì)象,B.html不需要,但使用其它方法。

Student.js

var StuObj = {
 getStu: function(name) {
 return new Student(name);
 }
}
/*構(gòu)造函數(shù)*/
function Student(name) {
 this.name = name;
 this.show = function() {
 console.log("Hello," + this.name);
 }
}

Common.js

function other1() {}
function other2() {}
(function($) {
 if($) {
 $.getStu("Tom").show();
 }
})(typeof StuObj=="undefined"?false:StuObj);

A.HTML

<!DOCTYPE html>
<html>
 <head>
 <meta charset="UTF-8">
 <title>A</title>
 </head>
 <body>
 <script src="js/Student.js" type="text/javascript" charset="utf-8"></script>
 <script src="js/common.js" type="text/javascript" charset="utf-8"></script>
 </body>
</html>

B.HTML

<!DOCTYPE html>
<html>
 <head>
 <meta charset="UTF-8">
 <title></title>
 </head>
 <body>
 <script src="js/common.js" type="text/javascript" charset="utf-8"></script>
 <script type="text/javascript">
 other1();
 </script>
 </body>
</html>

3.5.8、IIFE的變形

也許有人會(huì)說(shuō)IIFE將參數(shù)放在最后,需要移動(dòng)到文檔的末尾才能看到參數(shù),比較麻煩,那么可以將IIFE變形為如下形式:

(function(n){
 console.log(n);
 
 
 
 
 
 
 
 //認(rèn)為這里有30000代碼
 
 
 
 
 
 
 
 }(100));

如果中間有很長(zhǎng)的代碼,參數(shù)100只有到文檔的末尾才可以看得到,變形后的結(jié)果:

(function(exp){
 exp(100);
 }(function(n){
 console.log(n);
 //認(rèn)為這里有30000代碼
 }));

修改后的代碼中有兩個(gè)函數(shù)表達(dá)式,一個(gè)作為參數(shù),就是我們主要要完成的功能向控制臺(tái)輸出數(shù)字,另一個(gè)作來(lái)IIFE立即執(zhí)行的函數(shù),主要的功能函數(shù)變成的IIFE的參數(shù)了。

(function(win, doc, $) {
 }(window, document, jQuery));
 (
 function(library) {
 library(window, document, window.jQuery);
 }
 (function(window, document, $) {
 })
 );

bootstrap的寫(xiě)法:

+function(yourcode) {
 yourcode(window.jQuery, window, document);
 }(function($, window, document) {
 $(function() {}); //jQueryDOM加載完成事件
 });

結(jié)合call或apply的寫(xiě)法:

 (function(x){console.log(x)}).call(window,888);
 (function(x){console.log(x)}).apply(window,[999]);

輸出:888 999

四、示例下載

http://xiazai.jb51.net/201612/yuanma/javascript003-master_jb51.rar

以上就是本文的全部?jī)?nèi)容,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,同時(shí)也希望多多支持腳本之家!

相關(guān)文章

最新評(píng)論