JS是一門面向對象語言,其對象是用prototype屬性來模擬的,下面,來看看如何封裝JS對象.javascript
function Person (name,age,sex){ this.name = name; this.age = age; this.sex = sex; } Pserson.prototype = { constructor:Person, sayHello:function(){ console.log('hello'); } }
這種方式是比較常見的方式,比較直觀,可是Person() 的職責是構造對象,若是把初始化的事情也放在裏面完成,代碼就會顯得繁瑣,若是放在一個方法裏初始化會不會好點呢?java
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裏面申明,哪來的呢???jquery
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 執行,
函數app
_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;
測試一下ui
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 對象具備很強的集成性,能夠做爲函數調用,也能夠作爲對象調用,看成爲函數調用的時候,她能夠無需 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();
最後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對象封裝的方式就介紹到這裏,若有錯誤,望不吝賜教.