代码改变世界

javascript对象封装的常用方式

2017-09-14 22:52  好像在哪见过你  阅读(308)  评论(0编辑  收藏  举报

JS是门面向对象语言,其对象是用prototype属性来模拟的,下面例举下常用的封装方式。

常规封装

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

Person函数的职责是构造对象,如果把初始化的东西也放在里面,代码就会显得繁琐,于是有了升级版

升级版

function Person(info){
      this._init(info)
 }
Person.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;
}
o.__proto__ = constructor.prototype;这句是将构造函数的原型属性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。

类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并不是一个直观的做法,于是

Person.fn = Person.prototype = {
    constructor: Person,
    init: function(){
        this.name = info.name;
        this.sayHello =.function(){
            this.makeArray();
        }
    },
    makeArray: function (){
        console.log(this.name); 
    }
}

Person.fn.init.prototype = Person.prototype;

最后用闭包封装起来

var Person = (function(window){
    var Person = function(name) {
        return new Person.fn.init(name);
    }
    Person.prototype = Person.fn = {
        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;
})()    

最后介绍一种object.create()构造对象的方式,可以传递一个对象Person,构造一个p,并且使p继承Person

Person = {
     constructor: Person,
     sayHello: function(){
         console.log("hello");  
     }
}    

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为原型对象的对象。