JS 物件封裝的常用方式
1.常規封裝
function Person (name,age){
this.name = name;
this.age = age;
}
Pserson.prototype = {
constructor:Person,
say:function(){
console.log(`hello everyone!`);
}
}
2.升級版 (較常見)
function Person (example){
this._init_(example);
}
Pserson.prototype = {
constructor : Person,
_init_ : function(example) {
this.name = example.name;
this.age = example.age;
}
say:function(){
console.log(`hello everyone`);
}
}
3.new 的執行原理
var myNew = function(constructor, args) {
var obj = {};
obj .__proto__ = constructor.prototype;
var res = constructor.apply(obj , args);
var type = typeof res;
if ([`string`, `number`, `boolean`, `null`, `undefined`].indexOf(type) !== -1) {
return obj ;
}
return res;
}
解釋說明: 通過var obj = {} 構造一個空物件. 將建構函式的原型屬性prototype賦值給obj 的原型物件__proto__
,在執行 this.init(example); 這句話的時候,物件 obj 就可以在其原型物件中查詢_init_ 方法。(原型鏈)。
var res = constructor.apply(obj,args);
以obj為上下文呼叫函式,同時將引數作為陣列傳遞。那麼,
this._init_(example);
就會被 obj 執行
函式
_init_ : function(example) {
this.name = example.name;
this.age = example.age;
}
以 obj 為上下文呼叫,o也將擁有自己的 name,age屬性。
如果在建構函式中,return 複合型別,包括物件,函式,和正規表示式,那麼就會直接返回這個物件,否則,返回 obj
var type = typeof res;
if([`string`,`number`,`boolean`,`null`,`undefined`].indexOf(type) !== -1){
return obj;
}
return res;
舉例
function Person(name) {
this.name = name;
}
Person.prototype.say = function() {
console.log(this.name);
}
var jack = myFriend(Person, [`jack `]);
console.log(jack );
jack.say();
4.類jQuery 封裝
jQuery 物件具有很強的整合性,可以作為函式呼叫,也可以做為物件呼叫,當作為函式呼叫的時候,可以無需 new 而返回一個例項。
程式碼
var Person = function(info){
return new Person.prototype.init(info);
}
Person.prototype = {
constructor: Person,
init:function(){
this.name = example.name.
}
}
Person.prototype.init.prototype = Person.prototype;
- 這種封裝方式非常巧妙。 將物件的構造操作放在函式的裡面,而自己充當一個工廠。 不斷呼叫 prototype 並不是一個直觀的做法,於是
var Person = function(example){
return new Person.fn.init(example);
}
Person.fn = Person.prototype = {
constructor: Person,
init:function(){
this.name = info.name;
this.say = function(){
this.makeExp();
}
}
makeExp:function(){
console.log(this.name);
}
}
// 雖然把makeArray 等常用方法掛載到 Person.prorotype 下面,但還是會被 init 這個例項使用.
Person.fn.init.prototype = Person.fn;
最後用 閉包 封裝起來
var Person = (function(win) {
var Person = function(name) {
return new Person.fn.init(name);
}
Person.fn = Person.prototype = {
constructor: Person,
init: function(name) {
this.name = name;
this.say = function() {
this.makeExp();
}
},
makeExp: function() {
console.log(this.name);
}
}
Person.fn.init.prototype = Person.fn;
return Person;
})()
舉例:
var people = Person(`jack`);
console.log(people);
people.say();
object.create();
一種構造物件的方式, 可以傳遞一個物件Person,構造一個people,並且使people 繼承Person.
var Person = {
name: `jack`,
say: function() {
console.log(this.name);
}
}
var people = Object.create(Person);
console.log(people);
people.say();
物件Person的屬性成為了people的原型屬性,也就是說 people 原型繼承自 Person !
我們可以實現一個 Object.create()
Object.create = function(prototype){
function Fun(){};
Fun.prototype = prototype;
var obj = new Fun();
return obj;
}
說明:
將 Person 作為 建構函式的 原型屬性,就可以構造出 以Person 為原型物件的物件.
Object.create(原型); 建立一個繼承該原型的例項物件
關於此方法的一些注意事項:
(1)若傳參為Object.prototype,則建立的原型為Object.prototype,
- 和 new Object()建立的物件是一樣的 Object.create(Object.prototype) <==>new
Object();
(2)若傳參為空 或者 null,則建立的物件是沒有原型的,
- 導致該物件是無法用document.write()列印會報錯,
因為document.write()列印的原理是呼叫Object.prototype.toString()方法,
該物件沒有原型,也就沒有該方法,所以document.write()無法列印
由此延伸的知識點: 引用值都也是算作是物件, 所以都可以用document.write()列印; 原始值numebr, boolean,
string都有自己物件的包裝類, 藉助此機制也是可以用document.write()列印出的;
但undefined 和 null既不是引用值,也沒有對應的包裝類, 所以應該無法列印的,但大家會發現這兩個值也是可是用document.write()列印的, 因為這兩個值被設定為特殊值,
document.write()列印其是不用呼叫任何方法的,而是之直接列印其值