JS物件之封裝(二)

王瑞芳發表於2019-02-16

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()列印其是不用呼叫任何方法的,而是之直接列印其值

相關文章