自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

沒那么簡單 那些應該吃透的JavaScript概念

開發(fā) 前端
文章的目的是讓更多的程序員深入理解javascript的一些概念,其實關于這些,我們在可以在網上看到很多類似的內容,所以現(xiàn)在該是向深入理解的方向靠攏的時候了。

文章的目的是讓更多的程序員深入理解JavaScript的一些概念,其實關于這些,我們在可以在網上看到很多類似的內容,所以現(xiàn)在該是向深入理解的方向靠攏的時候了。

51CTO推薦閱讀:揭開JavaScript閉包的真實面目

一,function

從一開始接觸到js就感覺好靈活,每個人的寫法都不一樣,比如一個function就有N種寫法。如:functionshowMsg(){},varshowMsg=function(){},showMsg=function(){}。似乎沒有什么區(qū)別,都是一樣的嘛,真的是一樣的嗎,大家看看下面的例子:

  1. //函數(shù)定義:命名函數(shù)(聲明式),匿名函數(shù)(引用式)  
  2. //聲明式,定義代碼先于函數(shù)執(zhí)行代碼被解析  
  3. functiont1(){  
  4. dwn("t1");  
  5. }  
  6. t1();  
  7. functiont1(){  
  8. dwn("newt1");  
  9. }  
  10. t1();  
  11. //引用式,在函數(shù)運行中進行動態(tài)解析  
  12. vart1=function(){  
  13. dwn("newnewt1");  
  14. }  
  15. t1();  
  16. vart1=function(){  
  17. dwn("newnewnewt1");  
  18. }  
  19. t1();  
  20. //以上輸出:newt1,newt1,newnewt1,newnewnewt1 

可能想著應該是輸出t1,newt1,newnewt1,newnewnewt1,結果卻并不是這樣,應該理解這句話:聲明式,定義代碼先于函數(shù)執(zhí)行代碼被解析。如果深入一步,應該說是scope鏈問題,實際上前面兩個方法等價于window.t1,可以理解為t1是window的一個公有屬性,被賦了兩次值,以最后一次賦值為最終值。而后面兩個方法,可以理解為是t1是個變量,第四個方法的var去掉之后的結果仍然不會改變。

然而,當?shù)谒膫€方法改成functiont1(){}這樣的聲明式時,結果變成了newnewnewt1,newnewnewt1,newnewt1,newnewt1。前面兩個按照我的理解可以很好的理解為什么是這個答案,第三個也可以理解,但是最后一個輸出讓我比較糾結,希望有高手出現(xiàn)解答一下。另外匿名函數(shù)還有(function(){...})()這樣的寫法,最后一個括號用于參數(shù)輸入還有vart1=newfunction(){..}這樣的聲明,實際上t1已經是一個對象了。

  1. vart2=newfunction()  
  2. {  
  3. vartemp=100;//私有成員  
  4. this.temp=200;//公有成員,這兩個概念會在第三點以后展開說明  
  5. returntemp+this.temp;  
  6. }  
  7.  
  8. alert(typeof(t2));//object  
  9. alert(t2.constructor());//300  
  10. 除此之外,還有使用系統(tǒng)內置函數(shù)對象來構建一個函數(shù),例:  
  11. vart3=newFunction('vartemp=100;this.temp=200;returntemp+this.temp;');//這個位置加不加new結果都一樣,WHY  
  12. alert(typeof(t3));//function  
  13. alert(t3());//300 

二,創(chuàng)建對象

首先我們理解一下面向對象編程(Object-OrientedProgramming,OOP),使用OOP技術,常常要使用許多代碼模塊,每個模塊都提供特定的功能,每個模塊都是孤立的,甚至與其它模塊完全獨立。這種模塊化編程方法提供了非常大的多樣性,大大增加了代碼的重用機會??梢耘e例進一步說明這個問題,假定計算機上的一個高性能應用程序是一輛一流賽車。如果使用傳統(tǒng)的編程技巧,這輛賽車就是一個單元。

如果要改進該車,就必須替換整個單元,把它送回廠商,讓汽車專家升級它,或者購買一個新車。如果使用OOP技術,就只需從廠商處購買新的引擎,自己按照說明替換它,而不必用鋼鋸切割車體。不過大部分的論點是,JavaScript并不是直接的面向對象的語言,但是通過模擬可以做到很多面向對象語言才能做到的事,如繼承,多態(tài),封裝,JavaScript都能干。

  1. //以下三種構造對象的方法  
  2. //newObject,實例化一個Object  
  3. vara=newObject();  
  4. a.x=1,a.y=2;  
  5. //對象直接量  
  6. varb={x:1,y:2};  
  7. //定義類型  
  8. functionPoint(x,y){//類似于C#中的類  
  9. this.x=x;  
  10. this.y=y;  
  11. }  
  12. varp=newPoint(1,2);//實例化類 

第一種方法通過構造基本對象直接添加屬性的方法來實現(xiàn),第二種和第一種差不多,可以看成是第一種方法的快捷表示法。第三種方法中,可以以”類“為基礎,創(chuàng)造多個類型相同的對象。

#p#

三,對象屬性的封裝(公有和私有)

以例子來說明:

  1. functionList(){  
  2. varm_elements=[];//私有成員,在對象外無法訪問  
  3. m_elements=Array.apply(m_elements,arguments);  
  4. //此處模擬getter,使用時alist.length;  
  5. //等價于getName()方式:this.length=function(){returnm_elements.length;},使用時alist.length();  
  6. //公有屬性,可以通過"."運算符或下標來訪問  
  7. this.length={  
  8. valueOf:function(){  
  9. returnm_elements.length;  
  10. },  
  11. toString:function(){  
  12. returnm_elements.length;  
  13. }  
  14. }  
  15. //公有方法,此方法使用得alert(alist)相當于alert(alist.toString())  
  16. this.toString=function(){  
  17. returnm_elements.toString();  
  18. }  
  19. //公有方法  
  20. this.add=function(){  
  21. m_elements.push.apply(m_elements,arguments);  
  22. }  
  23. //私有方法如下形式,這里涉及到了閉包的概念,接下來繼續(xù)說明  
  24. //varadd=function()或functionadd()  
  25. //{  
  26. //m_elements.push.apply(m_elements,arguments);  
  27. //}  
  28. }  
  29. varalist=newList(1,2,3);  
  30. dwn(alist);//=alert(alist.toString()),輸出1,2,3  
  31. dwn(alist.length);//輸出3  
  32. alist.add(4,5,6);  
  33. dwn(alist);//輸出1,2,3,4,5,6  
  34. dwn(alist.length);//輸出6 

四,屬性和方法的類型

JavaScript里,對象的屬性和方法支持4種不同的類型:privateproperty(私有屬性),dynamicpublicproperty(動態(tài)公有屬性),staticpublicproperty/prototypeproperty(靜態(tài)公有屬性或原型屬性),staticproperty(靜態(tài)屬性或類屬性)。私有屬性對外界完全不具備訪問性,可以通過內部的getter和setter(都是模擬);動態(tài)公有屬性外界可以訪問,每個對象實例持有一個副本,不會相互影響;原型屬性每個對象實例共享唯一副本;類屬性不作為實例的屬性,只作為類的屬性。以下是例子:

  1. //動態(tài)公有類型,靜態(tài)公有類型(原型屬性)  
  2. functionmyClass(){  
  3. varp=100;//privateproperty  
  4. this.x=10;//dynamicpublicproperty  
  5. }  
  6. myClass.prototype.y=20;  
  7. //要想成為高級JavaScript階段,prototype和閉包必須得理解和適當應用  
  8. myClass.z=30;//staticproperty  
  9.  
  10. vara=newmyClass();  
  11. dwn(a.p)//undefined  
  12. dwn(a.x)//10  
  13. dwn(a.y)//20  
  14. a.x=20;  
  15. a.y=40;  
  16. dwn(a.x);//20  
  17. dwn(a.y);//40  
  18. delete(a.x);//刪除對象a的屬性x  
  19. delete(a.y);//刪除對象a的屬性y  
  20. dwn(a.x);//undefined  
  21. dwn(a.y);//20靜態(tài)公有屬性y被刪除后還原為原型屬性y  
  22. dwn(a.z);//undefined類屬性無法通過對象訪問  
  23. dwn(myClass.z); 

五,原型(prototype)

這里只講部分,prototype和閉包都不是幾句話都能講清楚的,如果這里可以給你一些啟蒙,則萬幸矣。習語”照貓畫虎“,這里的貓就是原型,虎是類型,可以表示成:虎.prototype=某只貓or虎.prototype=new貓()。因為原型屬性每個對象實例共享唯一副本,所以當實例中的一個調整了一個原型屬性的值時,所有實例調用這個屬性時都將發(fā)生變化,這點需要注意,以下是原型關系的類型鏈:

  1. functionClassA(){  
  2. }  
  3. ClassA.prototype=newObject();  
  4. functionClassB(){  
  5. }  
  6. ClassB.prototype=newClassA();  
  7. functionClassC(){  
  8. }  
  9. ClassC.prototype=newClassB();  
  10. varobj=newClassC();  
  11. dwn(objinstanceofClassC);//true  
  12. dwn(objinstanceofClassB);//true  
  13. dwn(objinstanceofClassA);//true  
  14. dwn(objinstanceofObject);//true  
  15. 帶默認值的Point對象:  
  16. functionPoint2(x,y){  
  17. if(x)this.x=x;  
  18. if(y)this.y=y;  
  19. }  
  20. //設定Point2對象的x,y默認值為0  
  21. Point2.prototype.x=0;  
  22. Point2.prototype.y=0;  
  23. //p1是一個默認(0,0)的對象  
  24. varp1=newPoint2();//可以寫成varp1=newPoint2也不會出錯,WHY  
  25. //p2賦值  
  26. varp2=newPoint2(1,2);  
  27. dwn(p1.x+","+p1.y);//0,0  
  28. dwn(p2.x+","+p2.y);//1,2  
  29. delete對象的屬性后,原型屬性將回到初始化的狀態(tài):  
  30. functionClassD(){  
  31. this.a=100;  
  32. this.b=200;  
  33. this.c=300 
  34. }  
  35. ClassD.prototype=newClassD();//將ClassD原有的屬性設為原型,包括其值  
  36. ClassD.prototype.reset=function(){//將非原型屬性刪除  
  37. for(vareachinthis){  
  38. deletethis[each];  
  39. }  
  40. }  
  41. vard=newClassD();  
  42. dwn(d.a);//100  
  43. d.a*=2;  
  44. d.b*=2;  
  45. d.c*=2;  
  46. dwn(d.a);//200  
  47. dwn(d.b);//400  
  48. dwn(d.c);//600  
  49. d.reset();//刪掉非原型屬性,所有回來原型  
  50. dwn(d.a);//100  
  51. dwn(d.b);//200  
  52. dwn(d.c);//300 

#p#

六,繼承

如果兩個類都是同一個實例的類型,那么它們之間存在著某種關系,我們把同一個實例的類型之間的泛化關系稱為繼承。C#和JAVA中都有這個,具體的理解就不說了。在JavaScript中,并不直接從方法上支持繼承,但是就像前面說的,可以模擬。

方法可以歸納為四種:構造繼承法,原型繼承法,實例繼承法和拷貝繼承法。融會貫通之后,還有混合繼續(xù)法,這是什么法,就是前面四種挑幾種混著來。以下例子來源于王者歸來,其中涉及到了apply,call和一些Array的用法,有興趣的可以自己在園子里搜索一下。

1,構造繼續(xù)法例子:

  1. //定義一個Collection類型  
  2. functionCollection(size)  
  3. {  
  4. this.size=function(){returnsize};//公有方法,可以被繼承  
  5. }  
  6.  
  7. Collection.prototype.isEmpty=function(){//靜態(tài)方法,不能被繼承  
  8. returnthis.size()==0;  
  9. }  
  10. //定義一個ArrayList類型,它"繼承"Collection類型  
  11. functionArrayList()  
  12. {  
  13. varm_elements=[];//私有成員,不能被繼承  
  14. m_elements=Array.apply(m_elements,arguments);  
  15.  
  16. //ArrayList類型繼承Collection  
  17. this.base=Collection;  
  18. this.base.call(this,m_elements.length);  
  19.  
  20. this.add=function()  
  21. {  
  22. returnm_elements.push.apply(m_elements,arguments);  
  23. }  
  24. this.toArray=function()  
  25. {  
  26. returnm_elements;  
  27. }  
  28. }  
  29.  
  30. ArrayList.prototype.toString=function()  
  31. {  
  32. returnthis.toArray().toString();  
  33. }  
  34. //定義一個SortedList類型,它繼承ArrayList類型  
  35. functionSortedList()  
  36. {  
  37. //SortedList類型繼承ArrayList  
  38. this.base=ArrayList;  
  39. this.base.apply(this,arguments);  
  40.  
  41. this.sort=function()  
  42. {  
  43. vararr=this.toArray();  
  44. arr.sort.apply(arr,arguments);  
  45. }  
  46. }  
  47.  
  48. //構造一個ArrayList  
  49. vara=newArrayList(1,2,3);  
  50. dwn(a);  
  51. dwn(a.size());//a從Collection繼承了size()方法  
  52. dwn(a.isEmpty);//但是a沒有繼承到isEmpty()方法  
  53.  
  54. //構造一個SortedList  
  55. varb=newSortedList(3,1,2);  
  56. b.add(4,0);//b從ArrayList繼承了add()方法  
  57. dwn(b.toArray());//b從ArrayList繼承了toArray()方法  
  58. b.sort();//b自己實現(xiàn)的sort()方法  
  59. dwn(b.toArray());  
  60. dwn(b);  
  61. dwn(b.size());//b從Collection繼承了size()方法 

2,原型繼承法例子

  1. //定義一個Point類型  
  2. functionPoint(dimension)  
  3. {  
  4.  
  5. this.dimension=dimension;  
  6. }  
  7.  
  8. //定義一個Point2D類型,"繼承"Point類型  
  9. functionPoint2D(x,y)  
  10. {  
  11. this.x=x;  
  12. this.y=y;  
  13. }  
  14. Point2D.prototype.distance=function()  
  15. {  
  16. returnMath.sqrt(this.x*this.x+this.y*this.y);  
  17. }  
  18. Point2D.prototype=newPoint(2);//Point2D繼承了Point  
  19.  
  20. //定義一個Point3D類型,也繼承Point類型  
  21. functionPoint3D(x,y,z)  
  22. {  
  23. this.x=x;  
  24. this.y=y;  
  25. this.z=z;  
  26. }  
  27. Point3D.prototype=newPoint(3);//Point3D也繼承了Point  
  28.  
  29. //構造一個Point2D對象  
  30. varp1=newPoint2D(0,0);  
  31. //構造一個Point3D對象  
  32. varp2=newPoint3D(0,1,2);  
  33. dwn(p1.dimension);  
  34. dwn(p2.dimension);  
  35. dwn(p1instanceofPoint2D);//p1是一個Point2D  
  36. dwn(p1instanceofPoint);//p1也是一個Point  
  37. dwn(p2instanceofPoint);//p2是一個Point 

以上兩種方法是最常用。

3,實例繼承法例子

在說此法例子之前,說說構造繼承法的局限,如下:

  1. functionMyDate()  
  2. {  
  3. this.base=Date;  
  4. this.base.apply(this,arguments);  
  5. }  
  6. vardate=newMyDate();  
  7. alert(date.toGMTString);//undefined,date并沒有繼承到Date類型,所以沒有toGMTString方法 

核心對象的某些方法不能被構造繼承,原因是核心對象并不像我們自定義的一般對象那樣在構造函數(shù)里進行賦值或初始化操作換成原型繼承法呢?,如下:

  1. functionMyDate(){}  
  2. MyDate.prototype=newDate();  
  3. vardate=newMyDate();  
  4. alert(date.toGMTString);//'[object]'不是日期對象,仍然沒有繼承到Date類型! 

現(xiàn)在,換成實例繼承法:

  1. functionMyDate()  
  2. {  
  3. varinstance=newDate();//instance是一個新創(chuàng)建的日期對象  
  4. instance.printDate=function(){  
  5. document.write("<p>"+instance.toLocaleString()+"</p>");  
  6. }//對instance擴展printDate()方法  
  7. returninstance;//將instance作為構造函數(shù)的返回值返回  
  8. }  
  9. varmyDate=newMyDate();  
  10. dwn(myDate.toGMTString());//這回成功輸出了正確的時間字符串,看來myDate已經是一個Date的實例了,繼承成功  
  11. myDate.printDate();//如果沒有returninstance,將不能以下標訪問,因為是私有對象的方法 

4,拷貝繼承法例子

  1. Function.prototype.extends=function(obj)  
  2. {  
  3. for(vareachinobj)  
  4. {  
  5. this.prototype[each]=obj[each];  
  6. //對對象的屬性進行一對一的復制,但是它又慢又容易引起問題  
  7. //所以這種“繼承”方式一般不推薦使用  
  8. }  
  9. }  
  10. varPoint2D=function(){  
  11. //……  
  12. }  
  13. Point2D.extends(newPoint())  
  14. {  
  15. //……  

這種繼承法似乎是用得很少的。

5,混合繼承例子

  1. functionPoint2D(x,y)  
  2. {  
  3. this.x=x;  
  4. this.y=y;  
  5. }  
  6. functionColorPoint2D(x,y,c)  
  7. {  
  8. Point2D.call(this,x,y);//這里是構造繼承,調用了父類的構造函數(shù)  
  9. //從前面的例子看過來,這里等價于  
  10. //this.base=Point2D;  
  11. //this.base.call(this,x,y);  
  12. this.color=c;  
  13. }  
  14. ColorPoint2D.prototype=newPoint2D();//這里用了原型繼承,讓ColorPoint2D以Point2D對象為原型 

 

【編輯推薦】

  1. 深入淺出JavaScript內存泄漏
  2. 拔開云霧見明月 透析JavaScript定時機制
  3. 揭開JavaScript閉包的真實面目
  4. JavaScript中的函數(shù)式編程實踐
  5. 三大秘訣助你輕松搞定JavaScript
責任編輯:王曉東 來源: 博客園
相關推薦

2015-04-30 10:12:13

開源云平臺OpenStack

2014-03-21 15:30:06

產品經理PM能力

2017-08-09 14:49:03

WebHTTPS瀏覽器

2016-07-25 12:58:07

SDN路由故障排查

2013-01-15 10:09:43

Windows Ser

2014-07-09 09:06:33

SDN自動化

2024-10-31 11:49:41

Kafka管理死信隊列

2013-02-19 09:21:01

Win 8

2020-10-30 09:33:01

分庫分表數(shù)據(jù)庫

2016-07-04 08:01:46

2021-03-29 13:00:50

代碼替換開發(fā)

2013-10-08 10:01:03

惠普開源SDN

2014-08-25 10:17:54

數(shù)據(jù)中心管理

2020-03-26 10:41:02

API網關大公司

2018-04-12 11:20:57

顯示器配件參數(shù)

2014-04-23 15:13:42

2018-10-19 11:15:34

云計算互聯(lián)網數(shù)據(jù)中心

2021-01-03 19:54:53

Python數(shù)據(jù)科學數(shù)據(jù)分析

2021-01-04 09:55:45

Python開發(fā)數(shù)據(jù)

2012-10-10 13:23:24

點贊
收藏

51CTO技術棧公眾號