對象(類)的封裝方式(面向對象的js基本知識)


上一個月一直忙於項目,沒寫過筆記,今天稍微空下來了一點

前幾天在寫項目的時候關於怎么去封裝每一個組件的時候思考到幾種方式,這里總結一下:

1、構造函數方式(類似java寫類的方式):把所有的屬性和方法全部掛在構造函數內部的this上:

 1 function Textarea(opts) {
 2     this.defaults = {
 3         //...這是一些默認屬性
 4     };
 5     this.options = $.extend(true, {}, this.defaults, opts);
 6     this.creatDom = function() {
 7         //...這里面很大一堆代碼
 8     };
 9     this.setVal = function() {
10         //...這是很大一堆代碼
11     };
12     this.getVal = function() {
13         //...這是很大一堆代碼
14     };
15 }

這種方法的優點是代碼比較緊湊,比較好理解和代碼的管理,但是這樣我們每次實例化一個對象的時候都會新開一段內存來存儲這個對象(包括方法和屬性)
我們改改:

 1 function Textarea(opts) {
 2     this.defaults = {
 3         //...這是一些默認屬性
 4     };
 5     this.options = $.extend(true, {}, this.defaults, opts);//這是覆蓋以后的屬性
 6     this.creatDom = creatDom;
 7     this.setVal = setVal;
 8     this.getVal = getVal;
 9 }
10 function creatDom() {
11     //...這是很大一堆代碼
12 }
13 function setVal() {
14     //...這是很大一堆代碼
15 }
16 function getVal() {
17     //...這是很大一堆代碼
18 }

這樣會節約一些內存:但是犧牲了代碼的緊湊度;
我們可以知道,每次實例化對象的時候其實三個方法其實是公用的,所以出現了第二種方式去定義對象

2、原型式寫法:把屬性和方法都掛在到對象的原型上:

 1 function Textarea() {}
 2 Textarea.prototype.defaults = {
 3     //...
 4 };
 5 Textarea.prototype.options = $.extend(true, {}, this.defaults);
 6 Textarea.prototype.creatDom = function() {
 7     //...
 8 };
 9 Textarea.prototype.setVal = function() {
10     //...
11 };
12 Textarea.prototype.getVal = function() {
13     //...
14 };
15 //當然也可以把所有屬性和方法放在對象上面然后再掛在prototype上:
16 function Textarea() {}
17 Textarea.prototype = {
18     defaults : {},
19     options : $.extend(true, {}, this.defaults),
20     creatDom : function() {},
21     setVal : function() {},
22     getVal : function() {}
23 };

但是這種方法是不可取的,因為這樣不能通過參數來構造對象實例(一般每個對象的屬性是不相同的);就像fe里面每個人名字不一致,但都能吃能笑能寫代碼;
舉個簡單的例子:

1 function Person(){}
2 Person.prototype.name = "winter";
3 Person.prototype.getName = function() { return this.name;}
4 new Person("summer").getName();//得到的還是winter的大名;

3、構造函數+原型結合的方式:

1 function Textarea(opts) {
2     this.defaults = {};
3     this.option =  $.extend(true, {}, this.defaults, opts);
4 }
5 Textarea.prototype = {
6     creatDom : function() {},
7     setVal : function() {},
8     getVal : function() {}
9 };

看看這種方式是不是很完美...
貌似還不完美,這樣Textarea.prototype還是在外面,
我們把它也拿到對象里面去:如下

1 function Textarea(opts) {
2     this.defaults = {};
3     this.option =  $.extend(true, {}, this.defaults, opts);
4     Textarea.prototype = {
5         creatDom : function() {},
6         setVal : function() {},
7         getVal : function() {}
8     };
9 }

現在看似好了,但是我們每次實例化的時候會發生什么?
都會去執行這對代碼:

1 Textarea.prototype = {
2     creatDom : function() {},
3     setVal : function() {},
4     getVal : function() {}
5 };

所以我們再做一個步驟,就是讓它只執行一次:

 1 function Textarea(opts) {
 2     this.defaults = {};
 3     this.option =  $.extend(true, {}, this.defaults, opts);
 4     if(!!this.init){
 5         Textarea.prototype = {
 6             creatDom : function() {},
 7             setVal : function() {},
 8             getVal : function() {}
 9         };
10         this.init = true;
11     }
12 }

OK!一般說來公共屬性寫在prototype下,需要在實例化的時候改變的屬性寫在this下
另外我們在實例化對象的時候(new)的時候需要在new的過程中就執行初始化函數:
比如上面的例子我們在var textarea = new Textarea(opts);的時候就想把creatDom函數執行了而不是new Textarea(opts).creatDom();
這時候我們就需要這樣:

 1 function Textarea(opts) {
 2     this.defaults = {};
 3     this.option =  $.extend(true, {}, this.defaults, opts);
 4     this.creatDom(this.options);
 5 }
 6 Textarea.prototype = {
 7     creatDom : function() {},
 8     setVal : function() {},
 9     getVal : function() {}
10 };

 

號外:構造函數下面的this

 1 var die = BlackBerry;
 2 function Phone(){
 3     console.log(this.die);
 4 }
 5 Phone()//BlackBerry
 6 var die = BlackBerry;
 7 function Phone(){
 8     this.die = "Nokia";
 9     console.log(this.die);
10 }
11 Phone()//Nokia

構造函數直接調用會把this當作全局window
所以以原型方式寫出的對象中沒有掛在this下面,直接調用構造函數將不會有這些屬性和方法
如果以構造函數的方式生成對象在構造函數直接調用的時候將在window下生成相應的對象和方法

原型下面的this

 1 function Phone() {}
 2 Phone.prototype = {
 3     name : "Nokia",
 4     init : function() {
 5         this.name = "BlackBerry";
 6     }
 7 };
 8 var myPhone = new Phone();
 9 myPhone.init();
10 console.log(myPhone.name);//BlackBerry
11 console.log(Phone.prototype.name);//Nokia

init里面的this指的是什么?Phone.prototype?

這里的this指的是調用的實例化對象myPhone;而不是原型對象,看看下面:
console.log(myPhone.hasOwnProperty("name"));//true
這里為true的原因是在調用myPhone.init()是給實例化對象添加樂一個name屬性

console.log(myPhone.hasOwnProperty("init"));//false
這里為false很明顯,因為start是原型上面的屬性而非實例化對象的屬性

我差點被騙了:我以為在代碼執行的時候myPhone.init();this.name = "BlackBerry";會覆蓋Phone.prototype下面的那么屬性


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM