趁着等服务端接口的一点点时间,网上看了几个关于js对象封装的例子,自己再重新手敲一遍,总结一下,温故而知新。(大艾斯镇楼)
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。
时间有限,未完待续。。。