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

JavaScript面試后的反思

開發(fā) 前端
為什么這么說,前些日子收到面試邀請,那就去試試唄,有幾年沒有面試過了吧。和面試官坐在沙發(fā)上,聊天式的他問我答,以下就是幾個javascript方面的問題。

寫此文目的是為了讓更多的程序員理解javascript的一些概念,對,是理解,而不是了解。我們已經(jīng)了解得夠多了,該是向深入理解的方向靠攏的時候了。

為什么這么說,前些日子收到面試邀請,那就去試試唄,有幾年沒有面試過了吧。和面試官坐在沙發(fā)上,聊天式的他問我答,以下就是幾個javascript方面的問題:

請創(chuàng)建一個對象,包括幾個公有屬性,接下來是為對象創(chuàng)建一個公有方法,然后為對象創(chuàng)建幾個私有屬性,一個私有方法。

說實話,這幾個問題我默名其妙,要是他讓我用jquery寫個拖動插件什么的,我估計我能寫挺好,原生的javascript,暈,雖然我看過jquery源碼解讀,但這些基本概念要命。

本文的例子輸出使用如下方法,便于查看:

  1. function dwn(s){document.write(s+"<br />");} 

function

從一開始接觸到j(luò)s就感覺好靈活,每個人的寫法都不一樣,比如一個function就有N種寫法,如:

  1. function showMsg(){}    
  2. var showMsg = function(){}   
  3. showMsg = function(){} 

似乎沒有什么區(qū)別,都是一樣的嘛,真的是一樣的嗎,大家看看下面的例子:

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

可能想著應(yīng)該是輸出t1,new t1,new newt1,new new new t1,結(jié)果卻并不是這樣,應(yīng)該理解這句話:聲明式,定義代碼先于函數(shù)執(zhí)行代碼被解析。

如果深入一步,應(yīng)該說是scope鏈問題,實際上前面兩個方法等價于window.t1,可以理解為t1是window的一個公有屬性,被賦了兩次值,以最后一次賦值為最終值。

而后面兩個方法,可以理解為是t1是個變量,第四個方法的var去掉之后的結(jié)果仍然不會改變。

然而,當?shù)谒膫€方法改成function t1(){}這樣的聲明式時,結(jié)果變成了new new new t1,new new new t1,new new t1,new new t1前面兩個按照我的理解可以很好的理解為什么是這個答案,第三個也可以理解,但是最后一個輸出讓我比較糾結(jié)。

另外匿名函數(shù)還有(function(){...})()這樣的寫法,最后一個括號用于參數(shù)輸入。

還有var t1=new function(){..}這樣的聲明,實際上t1已經(jīng)是一個對象了。

  1. var t2 = new function(){   
  2. var temp = 100; //私有成員   
  3. this.temp = 200; //公有成員,這兩個概念會在第三點以后展開說明   
  4. return temp + this.temp;}   
  5. alert(typeof(t2));   //object   
  6. alert(t2.constructor());  //300 

除此之外,還有使用系統(tǒng)內(nèi)置函數(shù)對象來構(gòu)建一個函數(shù),例:

  1. //這個位置加不加new結(jié)果都一樣,WHY   
  2. var t3 = new Function('var temp = 100;   
  3.  this.temp = 200;    
  4. return temp + this.temp;');   
  5.  alert(typeof(t3)); //function   
  6. alert(t3());  //300 

#p#

創(chuàng)建對象

首先我們理解一下面向?qū)ο缶幊蹋∣bject-Oriented Programming,OOP),使用OOP技術(shù),常常要使用許多代碼模塊,每個模塊都提供特定的功能,每個模塊都是孤立的,甚至與其它模塊完全獨立。這種模塊化編程方法提供了非常大的多樣性,大大增加了代碼的重用機會??梢耘e例進一步說明這個問題,假定計算機上的一個高性能應(yīng)用程序是一輛一流賽車。如果使用傳統(tǒng)的編程技巧,這輛賽車就是一個單元。如果要改進該車,就必須替換整個單元,把它送回廠商,讓汽車專家升級它,或者購買一個新車。如果使用OOP技術(shù),就只需從廠商處購買新的引擎,自己按照說明替換它,而不必用鋼鋸切割車體。

不過大部分的論點是,javascript并不是直接的面向?qū)ο蟮恼Z言,但是通過模擬可以做到很多面向?qū)ο笳Z言才能做到的事,如繼承,多態(tài),封裝,javascript都能干(沒有做不到,只是想不到):

  1. ///-----------------------------------------------   
  2. //以下三種構(gòu)造對象的方法   
  3. //new Object,實例化一個Object   
  4. var a = new Object();   
  5. a.x=1, a.y=2;//對象直接量   
  6. var b = {x:1,y:2};//定義類型   
  7. function Point(x,y){ //類似于C#中的類    
  8. this.x=x;    
  9. this.y=y;}   
  10. var p = new Point(1,2); //實例化類 

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

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

以例子來說明:

  1. function List(){   
  2. //私有成員,在對象外無法訪問,如果此處無var聲明,則m_elements將變成全局變量,這樣外部是可以直接訪問到的,如   
  3. alert(m_elements[0])       
  4. var m_elements=[];    
  5. m_elements=Array.apply(m_elements,arguments); //此處模擬getter,使用時alist.length;   
  6. //等價于getName()方式:   
  7. this.length=function()   
  8. {return m_elements.length;},//使用時alist.length();   
  9. //公有屬性,可以通過"."運算符或下標來訪問   
  10. this.length = {  valueOf:function(){   return m_elements.length;  },    
  11.  toString:function()   
  12. {   return m_elements.length;  } }    
  13. //公有方法,此方法使用得alert(alist)相當于   
  14. alert(alist.toString())   
  15. this.toString=function()   
  16. return m_elements.toString();}   
  17. //公有方法   
  18. this.add=function()   
  19. {m_elements.push.apply(m_elements,arguments);}   
  20. //私有方法如下形式,這里涉及到了閉包的概念,接下來繼續(xù)說明   
  21. //var add=function()或function add()   
  22. //{//m_elements.push.apply(m_elements,arguments);//}}   
  23. var alist=new List(1,2,3);dwn(alist);     
  24. //=alert(alist.toString()),輸出1,2,3   
  25. dwn(alist.length); //輸出3a   
  26. list.add(4,5,6);    
  27. dwn(alist);  //輸出1,2,3,4,5,6   
  28. dwn(alist.length); //輸出6 

#p#

屬性和方法的類型

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

以下是例子:

  1. ///----------------------------------------------   
  2. //動態(tài)公有類型,靜態(tài)公有類型(原型屬性)   
  3. function myClass(){   
  4. var p=100; //private property   
  5. this.x=10;  //dynamic public property   
  6. }   
  7. myClass.prototype.y=20; //static public property or prototype property, 
  1. //要想成為高級javascript階段,prototype和閉包必須得理解和適當應(yīng)用   
  2. myClass.z=30; //static property   
  3. var a=new myClass();   
  4. dwn(a.p) //undefined   
  5. dwn(a.x) //10   
  6. dwn(a.y) //20   
  7. a.x=20;   
  8. a.y=40;   
  9. dwn(a.x); //20   
  10. dwn(a.y); //40   
  11. delete(a.x); //刪除對象a的屬性x   
  12. delete(a.y); //刪除對象a的屬性y   
  13. dwn(a.x); //undefined   
  14. dwn(a.y); //20 靜態(tài)公有屬性y被刪除后還原為原型屬性y   
  15. dwn(a.z); //undefined 類屬性無法通過對象訪問   
  16. dwn(myClass.z); 

原型(prototype)

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

以下是原型關(guān)系的類型鏈:

  1. function ClassA(){}   
  2. ClassA.prototype=new Object();   
  3. function ClassB(){}   
  4. ClassB.prototype=new ClassA();   
  5. function ClassC(){}   
  6. ClassC.prototype=new ClassB();   
  7. var obj=new ClassC();   
  8. dwn(obj instanceof ClassC); //true   
  9. dwn(obj instanceof ClassB); //true   
  10. dwn(obj instanceof ClassA); //true   
  11. dwn(obj instanceof Object); //true   
  12. //帶默認值的Point對象:   
  13. function Point2(x,y)   
  14. {if (x)    
  15. this.x=x;   
  16. if (y)    
  17. this.y=y;}//設(shè)定Point2對象的x,y默認值為0   
  18. Point2.prototype.x=0;   
  19. Point2.prototype.y=0;//p1是一個默認(0,0)的對象   
  20. var p1=new Point2(); //可以寫成var p1=new Point2也不會出錯,WHY   
  21. //p2賦值   
  22. var p2=new Point2(1,2);   
  23. dwn(p1.x+","+p1.y); //0,0   
  24. dwn(p2.x+","+p2.y); //1,2delete對象的屬性后,原型屬性將回到初始化的狀態(tài):   
  25. function ClassD()   
  26. {this.a=100;   
  27. this.b=200;   
  28. this.c=300}   
  29. ClassD.prototype = new ClassD(); //將ClassD原有的屬性設(shè)為原型,包括其值   
  30. ClassD.prototype.reset = function(){ //將非原型屬性刪除   
  31. for (var each in this)    
  32.     {  delete this[each]; }}   
  33. var d = new ClassD();   
  34. dwn(d.a); //100   
  35. d.a*=2;   
  36. d.b*=2;   
  37. d.c*=2;   
  38. dwn(d.a); //200   
  39. dwn(d.b); //400   
  40. dwn(d.c); //600   
  41. d.reset(); //刪掉非原型屬性,所有回來原型   
  42. dwn(d.a); //100   
  43. dwn(d.b); //200   
  44. dwn(d.c); //300 

#p#

繼承

如果兩個類都是同一個實例的類型,那么它們之間存在著某種關(guān)系,我們把同一個實例的類型之間的泛化關(guān)系稱為繼承。C#和JAVA中都有這個,具體的理解就不說了。

在javascript中,并不直接從方法上支持繼承,但是就像前面說的,可以模擬。

方法可以歸納為四種:構(gòu)造繼承法,原型繼承法,實例繼承法和拷貝繼承法。融會貫通之后,還有混合繼續(xù)法,這是什么法,就是前面四種挑幾種混著來~

以下例子涉及到了apply,call和一些Array的用法:

構(gòu)造繼續(xù)法例子

  1. //定義一個Collection類型   
  2. function Collection(size){   
  3. this.size = function()   
  4. {return size};  //公有方法,可以被繼承   
  5. }   
  6.  Collection.prototype.isEmpty = function(){   //靜態(tài)方法,不能被繼承   
  7. return this.size() == 0;}    
  8. //定義一個ArrayList類型,它"繼承"Collection類型   
  9. function ArrayList(){   
  10. var m_elements = []; //私有成員,不能被繼承   
  11. m_elements = Array.apply(m_elements, arguments);//ArrayList類型繼承Collection     
  12. this.base = Collection;   
  13. this.base.call(this, m_elements.length);      
  14. this.add = function()  {      
  15. return m_elements.push.apply(m_elements, arguments);   
  16.   }   
  17.    this.toArray = function()   
  18.   {   return m_elements;  }}   
  19. ArrayList.prototype.toString = function()   
  20. {return this.toArray().toString();   
  21. }   
  22. //定義一個SortedList類型,它繼承ArrayList類型   
  23. function SortedList(){   
  24. //SortedList類型繼承ArrayList   
  25. this.base = ArrayList;   
  26. this.base.apply(this, arguments);   
  27. this.sort = function(){      
  28. var arr = this.toArray();   
  29.    arr.sort.apply(arr, arguments);  }   
  30. }//構(gòu)造一個ArrayList   
  31. var a = new ArrayList(1,2,3);   
  32. dwn(a);   
  33. dwn(a.size()); //a從Collection繼承了size()方法   
  34. dwn(a.isEmpty); //但是a沒有繼承到isEmpty()方法   
  35. //構(gòu)造一個SortedLis   
  36. tvar b = new SortedList(3,1,2);   
  37. b.add(4,0); //b 從ArrayList繼承了add()方法   
  38. dwn(b.toArray()); //b 從ArrayList繼承了toArray()方法   
  39. b.sort();  //b 自己實現(xiàn)的sort()方法   
  40. dwn(b.toArray());   
  41. dwn(b);   
  42. dwn(b.size()); //b從Collection繼承了size()方法 

原型繼承法例子

  1. //定義一個Point類型   
  2. function Point(dimension)   
  3. {   
  4. this.dimension = dimension;}//定義一個Point2D類型,"繼承"Point類型   
  5.     
  6.     
  7. function Point2D(x, y)   
  8. {   
  9. this.x = x;   
  10. this.y = y;}   
  11. Point2D.prototype.distance = function()   
  12. {return Math.sqrt(this.x * this.x + this.y * this.y);}   
  13. Point2D.prototype = new Point(2);  //Point2D繼承了Point   
  14. //定義一個Point3D類型,也繼承Point類型   
  15. function Point3D(x, y, z)   
  16. {this.x = x;   
  17. this.y = y;   
  18. this.z = z;}   
  19. Point3D.prototype = new Point(3);  //Point3D也繼承了Point    
  20. //構(gòu)造一個Point2D對象   
  21. var p1 = new Point2D(0,0);//構(gòu)造一個Point3D對象   
  22. var p2 = new Point3D(0,1,2);   
  23. dwn(p1.dimension);   
  24. dwn(p2.dimension);   
  25. dwn(p1 instanceof Point2D); //p1 是一個 Point2D   
  26. dwn(p1 instanceof Point); //p1 也是一個 Point   
  27. dwn(p2 instanceof Point); //p2 是一個Point 

以上兩種方法是最常用的。

實例繼承法例子

在說此法例子之前,說說構(gòu)造繼承法的局限,如下:

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

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

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

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

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

拷貝繼承法例子

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

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

混合繼承例子

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

原文鏈接:http://www.mxria.com/js/j201203151031.htm

責任編輯:張偉 來源: MXRIA
相關(guān)推薦

2017-02-13 11:45:19

JavaScriptfor循環(huán)

2009-07-03 11:39:00

綜合布線智能化

2014-07-03 15:06:04

信息安全網(wǎng)絡(luò)安全

2010-11-08 11:54:43

2013-01-24 09:49:58

創(chuàng)業(yè)華為辭職

2012-12-21 10:05:22

創(chuàng)業(yè)90后創(chuàng)業(yè)

2021-07-23 11:06:20

618拼團設(shè)計拼團

2023-09-13 08:37:56

程序員面試catch

2014-07-16 11:08:29

網(wǎng)絡(luò)·安全技術(shù)周刊

2014-02-13 17:21:23

技術(shù)創(chuàng)業(yè)

2011-10-17 08:29:33

Ubuntu 11.1思考

2021-04-07 22:31:51

人臉識別人工智能隱私

2021-08-08 11:17:58

谷歌Matt編程

2024-11-28 08:33:16

JavaScrip事件循環(huán)this

2022-08-12 09:35:36

JavaScript面試

2011-11-16 09:47:47

JavaScript

2023-06-26 08:24:23

JavaScriptAJAX

2023-04-04 11:20:40

GPT-4OpenAI

2009-02-27 09:37:17

面試技巧求職

2013-11-27 16:00:51

移動互聯(lián)網(wǎng)移動優(yōu)先
點贊
收藏

51CTO技術(shù)棧公眾號