最近在看《編寫高質量代碼-web前端修煉之道》,寫了3篇博客,寫寫感想。javascript
第一篇寫了關於javascript封裝以及模塊化插件設計。php
第二篇寫了關於javascript面向對象思想以及原型和構造器。前端
第三篇主要寫關於javascript的編寫風格以及細節設計問題。java
繼上一篇javascript進階,關於js插件開發的mvc思想,此次繼續寫篇博客,主要說說關於javascript的面向對象思想。python
1、關於javascript類的定義android
首先,javascript是面嚮對象語言,可是js沒有class類,而是經過:web
new funName( );
來聲明。segmentfault
javascript使用基於原型的語言,經過new實例化對象,其屬性和行爲來自兩部分,原型和構造函數。數組
當咱們聲明一個類時,同時生成了一個對應的原型。例如咱們聲明瞭:A這個類,會同時生成與這個類對應的原型。A.prototype指向原型,原型能夠經過coustructor指向構造函數。寫個代碼你就懂。數據結構
function A(){ } var x = A.prototype; var y = x.constructor; alert(y==A); //return true; console.log("也就是說A.prototype.constructor=A");
當咱們聲明類時候,新的構造函數會把舊的prototype原型給覆蓋掉。
給你看個例子。
function A(){ this.a="屬性a"; this.b="屬性b"; this.fun1=function(){ alert("這是函數對象1"); }; this.fun2=function(){ alert("這是函數對象2"); }; } var B = new A(); B.fun1=function(){ alert("你是笨蛋!!"); }; B.fun1(); //結果爲alert("你是笨蛋!!"); console.log("也就是說構造函數聲明的屬性會覆蓋原型的函數"); ```
從上面的例子裏咱們能夠看到,原型中的函數是會隨聲明的屬性或者方法是會被實例化過程聲明覆蓋。
通常來講,咱們習慣在構造函數裏放屬性,在原型裏面放方法。給你個例子看看:
/*===========構造函數放屬性,原型裏放方法============*/ function A(){ this.a="屬性a"; this.b="屬性b"; } A.prototype={ fun1:function(){ console.log("這是函數對象1,咱們把它放在原型裏"); }, fun2:function(){ console.log("這是函數對象2,咱們一樣也把它放在原型裏"); } }; var B = new A(); B.fun1(); B.fun2(); console.error("這樣就整潔多了。");
<br> **2、公有和私有** js裏面沒有相似php同樣的權限設置,但是若是我想要一個變量是私有屬性怎麼辦?須要注意的一點是,只要寫在原型裏的無論是屬性仍是方法,都是公有性的。因此要怎樣才能讓一個變量私有化呢?看看例子: ```js /*===============原型中的共有域和私有域================*/ function A(){ var a="屬性a是私有的,在類外面你是調用不到的。"; this.b="屬性b是公有的"; var fun1=function(){ console.log("函數對象1是私有的,在類外面你是調用不到的。"); }; this.fun2=function(){ console.log("函數對象2是共有的"); }; } A.prototype={ fun3:function(){ console.log("這是函數對象3,在原型裏的,只能是公有的"); } }; var B = new A(); B.a; //not found a; B.b; //返回正常 B.fun1(); //not found B.fun2(); B.fun3();
須要強調的一點是,原型中的屬性和方法,只存在一份,是公用的,在實例化的時候,並不會在複製一遍。因此,作到了代碼的重複利用,可是,若是把屬性和方法都放在構造函數裏,也同時致使了代碼修改的麻煩。
問題出來了,你想下,那咱們若是有一個屬性,不少函數都要調用他,想把它放在原型裏,可是又不想把讓它公有友化,怎麼破?怎麼破?
答案是:無法破。
因而,命名規則出來了,咱們規定,在命名前對一個下劃線,表示私有屬性。例如:
A.prototype={ _value:"咱們規定,這個屬性爲私有屬性(ps:其實它就是公有的)"; };
因而有些比較倔強的碼農們就提出來了一套新方案。請看:
/*=============私有與公有域==============*/ function A(){ this.a="屬性a是公有的。"; this.b="屬性b是公有的"; this.set_a=function(value){ this.a=value; }; this.get_a=function(){ return this.a; }; this.call=function(name){ console.log(this.get_a(name)); }; } var B = new A(); B.set_a("我把值改了"); B.call("a"); //return 我把值改了
看了好彆扭,可是這樣你就能夠在屬性或者方法的值改變時候,直接留下回調函數。
3、繼承
我在上一篇博客封裝過關於繼承的函數。由於在javascript裏面沒有繼承,可是繼承的思想又是存在於面嚮對象語言裏。
若是沒有函數,咱們要怎麼繼承?最笨的是,類A和類B,我把A的全部屬性和方法抄一遍。好傻啊,不適合。
/*==================關於聲明中的this==================*/ function A(){ this.a="屬性a是公有的"; this.b="屬性b是公有的"; } A.prototype={ say:function(){ console.log(this.a); } }; function B(value){ this.a=value; A(); } var C = new B(); //你覺得這麼就能繼承了麼??天真了,試試看 C.say(); //return undefind
哈哈,知道了吧,想知道爲何嗎?
js函數調用有兩種方法,
第一種是直接調用,此時,它做爲函數;
第二種是經過實例化,構造函數調用;
沒問題啊,可是,它們返回的this對象就不一樣了,第一種,做爲函數調用,返回的是window對象,可是第二種調用返回的是實例對象自己。因此說不能直接調用繼承。
咱們把this指向改下吧:
function A(){ this.a="屬性a是公有的"; this.b="屬性b是公有的"; } A.prototype={ say:function(){ console.log(this.a); } }; function B(value){ A.call(this,value); A(); } var C = new B(); //能夠了 C.say(); //找到值了
/*================相同原型繼承==================*/ function A(){ this.a="屬性a是公有的"; this.b="屬性b是公有的"; } A.prototype={ say:function(){ console.log(this.a); } }; var B =function(){ }; B.prototype = A.prototype; B.prototype.test=function(){ console.log("繼承後添加的函數"); }; var C = new B(); C.test(); //return console.log("繼承後添加的函數"); var D = new A(); D.test(); //return console.log("繼承後添加的函數");
爲何??爲何我只是在B中添加了test方法,可是我在A中也感染了??
由於javascript在賦值時候,若是判斷出值是布爾,字符串,數值型等基本數據類型,會直接複製值,可是,賦值,數組,方法,對象等複雜數據,一般都會地址複製,因此,把A的原型也改了。
咱們再試試,改回來,哪錯改哪。
function A(){ this.a="屬性a是公有的"; this.b="屬性b是公有的"; } A.prototype={ say:function(){ console.log(this.a); } }; var B =function(){ }; B.prototype = A.prototype; C.prototype.constructor=A; B.prototype.test=function(){ console.log("繼承後添加的函數"); }; var C = new B(); C.test(); //return console.log("繼承後添加的函數"); var D = new A(); D.test(); //return not defind
這樣就行了。
最後給下,extend的具體函數把,這樣就不要一個一個地來弄了,你只要調用函數就行了。
function extend(subClass, superClass){ var C=function(){}; C.prototype=superClass.prototype; subClass.prototype=new C(); subClass.prototype.constructor=subClass; subClass.superClass=superClass.prototype; if(superClass.prototype.constructor == Object.prototype.constructor){ superClass.prototype.constructor=superClass; } } /*=====搞定了=====*/
寫下最近的在作什麼吧:
看了《javascript高質量代碼》;
給新生培訓了下,寫了篇博客;
看了一點點的php數據結構
寫寫接下來作什麼吧:
《python基礎教程》(華哥的項目,日誌分析系統)
《精通android 4》(東哥)
期末了,要開始複習了。
(睡覺去。。。)
夏日小草
2013/12/3 1:57:07
(ps:若是有出錯,求指點出來。)