美文网首页
javascript 对象封装的常用方式

javascript 对象封装的常用方式

作者: _孙大善 | 来源:发表于2017-04-18 21:06 被阅读0次

趁着等服务端接口的一点点时间,网上看了几个关于js对象封装的例子,自己再重新手敲一遍,总结一下,温故而知新。(大艾斯镇楼)

QQ图片20170418093319.jpg

JS是一门面向对象语言,其对象是用prototype属性来模拟的,下面,来看看如何封装JS对象。

常规封装
function Person(name, age, sex){
    this.name = name;
    this.age = age;
    this.sex = sex;
}

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

这种方式是比较常见的,比较直观,但是Person()的职责是构造对象,如果把初始化的事情放在里面完成,代码就会显得繁琐,如果放在一个方法里初始化会不会好点呢?

升级版(常见)
function Person(info){
    this._init_(info);
}

Person.prototype = {
    constructor: Person,
    _init_: function(info){
        this.name = name;
        this.age = age;
        this.sex = 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(0, 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); //{name: pawn}
o1.sayHello(); //pawn

OK,大功告成!

此外,再补充几点,
只有函数才有prototype属性,这个属性值为一个object对象,
实例对象时没有这个属性的,实例对象通过proto这个内部属性([[prototype]])来串起一个原型链的,通过这个原型链可以查找属性,方法,
通过new操作符初始化一个函数对象的时候就会构建出一个实例对象,函数对象的prototype属性指向的对象就是这个实例对象的原型对象,也就是proto指向的对象
所有构造器/函数的proto都指向Function.prototype,它是一个空函数(Empty function)

Number.__proto__ === Function.prototype  // true
Boolean.__proto__ === Function.prototype // true
String.__proto__ === Function.prototype  // true
Object.__proto__ === Function.prototype  // true
Function.__proto__ === Function.prototype // true
Array.__proto__ === Function.prototype   // true
RegExp.__proto__ === Function.prototype  // true
Error.__proto__ === Function.prototype   // true
Date.__proto__ === Function.prototype    // true

JavaScript中有内置(build-in)构造器/对象共计12个(ES5中新加了JSON),这里列举了可访问的8个构造器。剩下如Global不能直接访问,Arguments仅在函数调用时由JS引擎创建,Math,JSON是以对象形式存在的,无需new。它们的proto是Object.prototype。如下

Math.__proto__ === Object.prototype  // true
JSON.__proto__ === Object.prototype  // true

Function.prototype也是唯一一个typeof XXX.prototype为 “function”的prototype。其它的构造器的prototype都是一个对象。如下

console.log(typeof Function.prototype) // function
console.log(typeof Object.prototype)   // object
console.log(typeof Number.prototype)   // object
console.log(typeof Boolean.prototype)  // object
console.log(typeof String.prototype)   // object
console.log(typeof Array.prototype)    // object
console.log(typeof RegExp.prototype)   // object
console.log(typeof Error.prototype)    // object
console.log(typeof Date.prototype)     // object
console.log(typeof Object.prototype)   // object

相信都听说过JavaScript中函数也是一等公民,那从哪能体现呢?如下

console.log(Function.prototype.__proto__ === Object.prototype) // true

最后Object.prototype的proto是谁?

Object.prototype.__proto__ === null  // true

已经到顶了,为null。

时间有限,未完待续。。。

相关文章

网友评论

      本文标题:javascript 对象封装的常用方式

      本文链接:https://www.haomeiwen.com/subject/pjbfzttx.html