JavaScript 自定义对象
- 模式主要有工厂模式,构造函数方式,原型模式, 组合模式,动态原型模式;
例子:
//工厂模式:对象识别问题,代码复用问题,无共享区域 function createPerson(name, age) { var o = new Object(); o.name = name; o.age = age; o.sayName = function() { alert(this.name); }; return o; }
//构造函数:代码复用问题,无共享区域 function Person(name, age) { this.name = name; this.age = age; this.sayName = function() { alert(this.name); }; }
//原型模式: 对于函数来说可以,符合我们的要求,实现了共享;对于基本量来说,我们可以通过对实例新建一个同名的属性来得到实例变量;但是问题会出现引用类型,如果是引用类型的话,尽管也可以跟基本类型一样在实例 上新建一个同名的来覆盖,但在使用上就有些不合理(因为对象多半是有函数的),当我们直接在实例上调用了引用类型的方式时,其实是修改了原型中的对象。 function Person() { } //使用prototype属性逐一添加 var name = "Kin", age = 12; Person.prototype.name = name; Person.prototype.age = age; Person.prototype.sayName = function() { alert(this.name); }
Person.prototype.friends = ["Mik", "Sell"];
//利用对象字面量重写prototype Person.prototype = { constructor : Person, name : "Kin", age : 12, sayName : function() { alert(this.name); },
friends : ["Mik", "Sell"]
};
//引用类型的问题在于,当我一个实例对象person1 调用了person1.friends.push("Jon")时,其实是修改原型中的friends,所以效果也就会出现在其他实例上了,当然我们可以直接复制(利用slice()来生成一个新的数组)并新建一个新的对象在person1上,也即person1.friends = person1.friends.slice(0, person1.friends.length).但这样往往比较麻烦,也容易忘记。
//组合模式(组合使用构造函数和原型,不足是看起来不像是一个对象的定义方式) //定义实例变量 function Person(name, age) { this.name = name; this.age = age; this.friends = ["shell", "dos"]; } //定义类变量 Person.prototype = { constructor : Person, sayName : function() { alert(this.name); } }
//动态原型模式 function Person(name, age) { this.name = name; this.age = age; if(typeof this.sayName != "function") { Person.prototype.sayName = function() { alert(this.name); }; //other also here } }
补充说明
- 在function 中定义的实例变量(也就是用this指定的)在没有用new 实例化之前在内存中是不存在的。
- 在函数创建之后(不用调用),该函数就会被创建一个prototype的属性(这个与在function中定义的不一样)。
- 在利用构造函数实例化一个“对象”后,该对象会有一个[[prototype]]内部属性,这个属性的值是构造函数的原型对象的引用(也是因为这个机制才可以实现“类机制”和“继承机制”),但是我们无法直接访问这个属性,但在主流浏览器都支持实例化对象有一个“__proto__”属性,该属性值等于[[prototype]].
- 在定义function后若是显示使用函数名去添加属性的话,此时的属性是已初始化的,也就是说在内存中分配了内存,但是这个内存区域的地址只有用函数名的引用才可以访问,而其实例对象是无法访问的;
- 在javascript中是没有类的定义的,其实现主要:this来设定作用域(模仿实例对象),prototype来实现继承的方式
- 在函数中定义的变量和函数如果是作为实例变量的,一定要用this.名称,否则会被解析器视为局部变量或是全局变量。
- 其实JS的构造函数对于实例化对象而言,就是一个方法,一个去为自己添加属性的方法,在这个方法中可能会运用到一些局部变量(没有用this.*=*(*代表变量),那么这些变量在函数出栈后,就会被销毁。
相关代码说明:
function Person() { var test = "test"; //局部变量 this.here = "here"; //实例变量 this.sayAge = function() { return "age"; }; } console.log(Person.here); //undefined console.log(Person.sayAge()); //Person.sayAge is not a function //在外部定义 Person.sayAge2 = function() { return "age"; } Person.here2 = "outhere"; console.log(Person.here2); //outhere console.log(Person.sayAge2()); //age Person.prototype = { constructor : Person, name : "Kin", age : 12, friends : ["Sell", "Mik"], sayName : function() { return "name"; } } person1 = new Person(); person2 = new Person();
person1.sayAge2(); //person1.sayAge2 is not a function
相关图例: