JavaScript关于对象的总结
//工厂模式 function creatCar(color,host,size){ var o = new Object(); o.color = color; o.host = host; o.size = size; o.tellColor = function(){alert(o.color);}; return o; } var myCar = creatCar("red","Kate",4); myCar.tellColor(); ************************************************************ //构造函数模式 function CreateCar(color,host,size){ this.color=color; this.host=host; this.size=size; this.tellColor=function(){ alert(this.color); }; } 【1】 var myCar = new CreateCar("red","Kate",4); // 必须用new关键字 myCar.tellColor(); 此时myCar里面有一个constructor属性,该属性指向CreateCar 一般用这个来检验类型:alert(myCar instanceof CreateCar); 任何函数用new来调用,都可以当作为构造函数。 【2】 如果当做普通函数来调用,就是如下情形: 在全局作用域中调用一个函数时,this对象总是指向global对象,在浏览器中就是window对象 CreateCar("red","Kate",4); window.tellColor(); 【3】 也可以这样:用函数的方法call在对象o的作用域中调用CreateCar方法 var o = new Object(); CreateCar.call(o,"red","Kate",4); o.tellColor(); 【4】 该方式的问题:每个方法需要在每个实例上重新创建一遍。因此可以做如下修改: this.tellColor= new Function("alert(this.color)"); //注意这个Function首字母大写 【5】 其实,创建相同的Function实例其实没有必要,这里不需要把函数绑定到特定的对象上面: function CreateCar(color,host,size){ this.color=color; this.host=host; this.size=size; this.tellColor=tellColor; } function tellColor(){ alert(this.color); } 然而这就没什么封装性可言了。。。 ********************************************************** //原型模式 每个函数都有一个prototype属性,其指向一个对象。该对象包含可由特定类型所有实例共享的属性和方法。所以,把公共的部分移到prototype里面就行了。 function CreateCar(color,host,size){ this.color=color; this.host=host; this.size=size; } CreateCar.prototype.tellColor = function(){ alert(this.color); }; 【1】 var o = new CreateCar("red","Kate",4); o.tellColor(); 但是这种方法,用call函数是不行的。 【2】 prototype对象有constructor属性,该属性指向prototype属性所在函数的指针。 alert(CreateCar.prototype.constructor==CreateCar); //true 但是如果直接用CreateCar.prototype={ };的形式,constructor就不会指向CreateCar了。此时要用到defineProperty(); 对象里有指向prototype的指针 【3】 可以通过对象实例访问保存在原型中 值,但不能通过对象重写原型中的值。然而原型中做的任何修改都能在实例中立即显现出来,哪怕在修改前就有实例化。 但是如果直接用CreateCar.prototype={ };的形式,实例与原型的联系就被切断。里面新定义的属性和方法也不好用。 【4】 实例中的属性会屏蔽原型中相应的属性。如果delete该属性,那么就能访问到原型中相应的属性了 【5】 原型中不能写“引用型”的属性。比如数组、对象。因为存进去的只是一个指针。在实例化不同对象的时候,一个修改了,另一个也会跟着修改。 【6】 CreateCar.prototype.tellColor = function(){ alert(this.color); }; 这个可以写在构造函数的里面,但是需要先判断方法是否存在: function CreateCar(color,host,size){ this.color=color; this.host=host; this.size=size; if(typeof this.tellColor != "function"){ CreateCar.prototype.tellColor = function(){ alert(this.color); }; } } if的那一块只在初次调用构造函数的时候才会执行 *********************************************************** 继承: 子的原型=父的实例 function CreateCar(){ this.color="black"; if(typeof this.tellColor != "function"){ CreateCar.prototype.tellColor = function(){ alert(this.color); }; } } function CreateSmallCar(){ } CreateSmallCar.prototype = new CreateCar(); var o = new CreateSmallCar(); o.tellColor(); 【1】 可以新增CreateSmallCar里原型的方法,CreateSmallCar原型的方法也可以覆盖掉父CreateCar中原型的方法。但是这必须在 CreateSmallCar.prototype = new CreateCar(); 这句之后进行 【2】 另外,不能用CreateSmallCar.prototype = { };的方式增加新的方法,这样会重写圆形链,导致之前的语句无效 【3】 如果CreateCar的构造函数中包含引用型属性,那么CreateSmallCar.prototype里面也会包含该类属性,就会出现之前所说的问题 解决方案------在子的构造函数中调用父构造函数,可以用call function CreateSmallCar(){ CreateCar.call(this); } 【4】 没法传参,于是下面的是最常用的方式 function CreateCar(color){ this.color=color; if(typeof this.tellColor != "function"){ CreateCar.prototype.tellColor = function(){ alert(this.color); }; } } function CreateSmallCar(color,owner){ this.owner=owner; CreateCar.call(this,color); } CreateSmallCar.prototype = new CreateCar(); CreateSmallCar.prototype.constructor=CreateSmallCar; //因为它的上一句,使得CreateSmallCar.prototype被重写。因此需要这样改一下。 var o = new CreateSmallCar("red","Kate"); o.tellColor();