標籤:

JS 對象封裝的常用方式

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

常規封裝

function Person (name,age,sex){ this.name = name; this.age = age; this.sex = sex;}Pserson.prototype = { constructor:Person, sayHello:function{ console.log("hello"); }}

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

升級版 (常見)

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 的執行過程可以用下面一個函數來代替

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_ 方法。(原型鏈)。

之後這句話 就是精髓了。

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

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

this._init_(info);

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

_init_ : function(info) { this.name = info.name; this.age = info.age; this.sex = info.sex; }

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

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

var type = typeof res; if(["string","number","boolean","null","undefined"].indexOf(type) !== -1){ return o; } return res;

測試一下

function Person(name) { this.name = name; } Person.prototype.sayHello = function { console.log(this.name); } var o1 = myNew(Person, ["pawn"]); console.log(o1); o1.sayHello;

OK 吧

類jQuery 封裝

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

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

先看代碼

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 並不是一個直觀的做法,於是

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;

最後用 閉包 封裝起來

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; });

測試一下

var p = Person("pawn"); console.log(p); p.sayHello;

object.create;

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

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

Object.create = function(prototype){ function Func{}; Func.prototype = prototype; var o = new Func; return o;}

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

測試一下

OK

關於 JS對象封裝的方式就介紹到這裡,如有錯誤,望不吝賜教.


推薦閱讀:

婚外情的種種跡象和應對方式
愛一個人最好的方式
硬拉動作圖解、硬拉的四種變化方式
女生最討厭的10種追求方式,90%的男生不知道!
吃雞的方式有很多,但這種最爽!

TAG:方式 |