JS 對象封裝的常用方式


JS 對象封裝的常用方式

JS是一門面向對象語言,其對象是用prototype屬性來模擬的。來看看如何封裝JS對象.

常規封裝

?
1
2
3
4
5
6
7
8
9
10
11
12
function Person (name,age,sex){
     this .name = name;
     this .age = age;
     this .sex = sex;
}
 
Pserson.prototype = {
     constructor:Person,
     sayHello:function(){
         console.log( 'hello' );
     }
}

 這種方式是比較常見的方式,比較直觀,但是Person() 的職責是構造對象,如果把初始化的事情也放在里面完成,代碼就會顯得繁瑣,如果放在一個方法里初始化會不會好點呢?

 

升級版 (常見)

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Person (info){
     this ._init_(info);
}
 
Pserson.prototype = {
     constructor : Person,
     _init_ : function(info) {
         this .name = info.name;
         this .age = info.age;
         this .sex = info.sex;
     }
     sayHello:function(){
         console.log( 'hello' );
     }
}

 可是,說到這里就發現,name,age,sex 並沒有在Person里面申明,哪來的呢???

 

new 的執行原理

new 的執行過程可以用下面一個函數來代替

?
1
2
3
4
5
6
7
8
9
10
var myNew = function(constructor, args) {
        var o = {};
        o.__proto__ = constructor.prototype;
        var res = constructor.apply(o, args);
        var type = typeof res;
        if ([ 'string' , 'number' , 'boolean' , 'null' , 'undefined' ].indexOf(type) !== -1) {
            return o;
        }
        return res;
    }

 

解釋:
首先通過 var o = {} 構造一個空對象.
然后將 構造函數的原型屬性prototype賦值給o 的原型對象__proto__ 。這樣,在執行 this.init(info); 這句話的時候,對象 o 就可以在其原型對象中查找_init_ 方法。(原型鏈)。
之后這句話 就是精髓了。

?
1
var res = constructor.apply(o,args);

 以o為上下文調用函數,同時將參數作為數組傳遞。那么,

?
1
this ._init_(info);

 這句話就會被 o 執行,函數

?
1
2
3
4
5
_init_ : function(info) {
        this .name = info.name;
        this .age = info.age;
        this .sex = info.sex;
    }

 

以 o 為上下文調用,o也將擁有自己的 name,age,sex 屬性。

如果在構造函數中,return 復合類型,包括對象,函數,和正則表達式,那么就會直接返回這個對象,否則,返回 o

?
1
2
3
4
5
var type = typeof res;
     if ([ 'string' , 'number' , 'boolean' , 'null' , 'undefined' ].indexOf(type) !== -1){
         return o;
     }
     return res;

 測試一下

?
1
2
3
4
5
6
7
8
9
function Person(name) {
      this .name = name;
  }
  Person.prototype.sayHello = function() {
      console.log( this .name);
  }
  var o1 = myNew(Person, [ 'pawn' ]);
  console.log(o1);
  o1.sayHello();

 

 

 

call方法:
語法:call([thisObj[,arg1[, arg2[,   [,.argN]]]]])
定義:調用一個對象的一個方法,以另一個對象替換當前對象。
說明:
call 方法可以用來代替另一個對象調用一個方法。call 方法可將一個函數的對象上下文從初始的上下文改變為由 thisObj 指定的新對象。
如果沒有提供 thisObj 參數,那么 Global 對象被用作 thisObj。

apply方法:
語法:apply([thisObj[,argArray]])
定義:應用某一對象的一個方法,用另一個對象替換當前對象。
說明:
如果 argArray 不是一個有效的數組或者不是 arguments 對象,那么將導致一個 TypeError。
如果沒有提供 argArray 和 thisObj 任何一個參數,那么 Global 對象將被用作 thisObj, 並且無法被傳遞任何參數。

 

 

 

類jQuery 封裝

 

 這種方式是我從 jQuery 那里學來的。

jQuery 對象具有很強的集成性,可以作為函數調用,也可以做為對象調用,當作為函數調用的時候,她可以無需 new 而返回它的一個實例,很方便。

代碼

?
1
2
3
4
5
6
7
8
9
10
11
var Person = function(info){
     return new Person.prototype.init(info);
}
 
Person.prototype = {
     constructor: Person,
     init:function(){
         this .name = info.name.
     }
}
Person.prototype.init.prototype = Person.prototype;

 這種封裝方式非常巧妙。
將對象的構造操作放在函數的里面,而自己充當一個工廠。
不斷調用 prototype 並不是一個直觀的做法,於是

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var Person = function(info){
     return new Person.fn.init(info);
}
 
Person.fn = Person.prototype = {
     constructor: Person,
     init:function(){
         this .name = info.name;
         this .sayHello = function(){
             this .makeArray();
         }
     }
     makeArray:function(){
         console.log( this .name);
     }
}
// 這句話的作用
// 雖然把makeArray 等常用方法掛載到 Person.prorotype 下面,但還是會被 init 這個實例使用.
Person.fn.init.prototype = Person.fn;

 最后用 閉包 封裝起來

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var Person = (function(window) {
         var Person = function(name) {
             return new Person.fn.init(name);
         }
 
         Person.fn = Person.prototype = {
             constructor: Person,
             init: function(name) {
                 this .name = name;
                 this .sayHello = function() {
                     this .makeArray();
                 }
             },
             makeArray: function() {
                 console.log( this .name);
             }
         }
 
         Person.fn.init.prototype = Person.fn;
 
         return Person;
     })();

 測試一下

?
1
2
3
var p = Person( 'pawn' );
    console.log(p);
    p.sayHello();

 

 

 

object.create()

js也提供了一種構造對象的方式,object.create(); 可以傳遞一個對象Person,構造一個p,並且使p 繼承Person.

?
1
2
3
4
5
6
7
8
9
var Person = {
       name: 'pawn' ,
       sayHello: function() {
           console.log( this .name);
       }
   }
   var p = Object.create(Person);
   console.log(p);
   p.sayHello();

 

 

 

可以看到,對象Person的屬性成為了p的原型屬性,也就是說 p 原型繼承自 Person !

我們可以實現一個 Object.create()

?
1
2
3
4
5
6
Object.create = function(prototype){
    function Func(){};
    Func.prototype = prototype;
    var o = new Func();
    return o;
}

 在這里,我們將 Person 作為 構造函數的 原型屬性,就可以構造出 以Person 為原型對象的對象.

 


免責聲明!

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



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