JavaScript 组件化开发之路(一)

 

JavaScript中的对象属性

深入了解JavaScript中的对象以及对象中的属性,是构建可复用组件的前提。

对象的创建方式,常用的有两种:

  • 通过对象字面量创建

    var obj = {x:1}

  • 通过构造函数创建

    var obj = new Object()

我们可以用for-in来遍历并输出对象的属性。

var obj = {
    x: 1,
    y: 2,
    vars:['a','b','c'],
    add: function(){return this.x+this.y}
}

for(var prop in obj){
    console.log(prop)
}
//输出 x, y, vars,add

在组件的开发中,我们经常要用到对象的继承,现在我们创建一个对象,它继承自obj,用es5里的方法,可以很容易的实现

var obj2 = Object.create(obj)
for(var prop in obj2){
    console.log(prop)
}
//输出 x, y, vars,add

可以看到,obj2并没有自己的实例属性,但是,我们用for-in仍然可以得到三个属性。这三个属性继承自obj。 由于es5的这个方法并没有得到所有浏览器的支持,我们需要尝试自己实现对象的继承,去更加深入的了解继承的原理。

var inherit = function(obj){
    function F(){}
    F.prototype = obj
    return new F()
}

var obj3 = inherit(obj)

for(var prop in obj3){
    console.log(prop)
}
//x, y, vars,add

看上去不错,我们也实现了所谓的继承,但是觉得似乎哪里有点不对劲?我们再创建一个对象试试

var obj4 = inherit(obj)

for(var prop in obj4){
    console.log(prop)
}
//x,y.vars,add

我们试着操作obj3的属性

obj3.x=0
console.log(obj3.x) //0
console.log(obj4.x) //1

貌似没什么问题,继续

obj.vars.push('d')
console.log(obj3.vars) //["a", "b", "c", "d"]
console.log(obj4.vars) //["a", "b", "c", "d"]

出大事了。对一个对象的修改,影响到了另外一个对象。组件设计中,如果一个组件的修改,会影响到同类的其它实例,那还有什么独立性可言? 发生这种结果的原因, 就在我们实现的inherit方法中。在这个实现继承的方法中,我们首先创建了一个新的构造函数。这个构造函数的prototype指向了我们要继承的对象。因此,下面调用这个构造函数产生的对象,原型就是obj。当我们调用obj3.vars时,obj3本身并没有vars这个属性,于是它顺着原型链向上查找,在obj中找到了vars这个属性。这个属性的值是一个数组,数组属于引用类型,也就是说obj.vars属性中保存的只是一个指针(地址)。我们对obj3.vars得到的也是这个指针。针对这个指针指向的数组,进行了push操作,结果就是改变了这个指针指向的数组的值。当我们读取obj4的vars属性时,由于obj4本身也没有这个属性,它也会顺着原型链向上查找,找到obj.vars,而这时的obj.vars指向的数组已经被obj3的操作改变了。

这种继承方式显然无法满足我们的需求。我们希望每个继承而来的对象,在享有共有属性和方法的同时,也有自己私有的一些属性和方法。这些私有的属性不应该被共享,也不可以被别的对象修改。

下面是另一个实现继承的方式

var myClass = function(){
    this.vars = ['a','b','c']
    this.x = 1
}
myClass.prototype.y=1
myClass.prototype.say=function(){console.log('hi')}
myClass.prototype.publicArr=[1,2,3]
var my1 = new myClass
var my2 = new myClass

my1.vars.push('d')
console.log(my1.vars) // ['a','b','c','d']
console.log(my2.vars) // ['a','b','c']

我们把每个对象的私有属性,定义在构造函数内部,而把那些需要共同享用的属性,放在构造函数的prototype属性中。这样,当我们创建对象时,每个对象都会拥有自己的私有属性(vars,x),也可以通过原型链,查找到原型中的属性。

console.log(my1.y) //1
my1.say() //'hi'
console.log(my2.y) //2
my2.say() //'hi'

//共享的属性,可以被其它的对象改变
my1.publicArr.push(4)
console.log(my1.publicArr) //[1, 2, 3, 4]
console.log(my2.publicArr) //[1, 2, 3, 4]
posted @ 2016-05-21 23:31  杯酒红尘  阅读(741)  评论(1编辑  收藏  举报