javascript 创建对象 模式总结
内容总结自《javascript高级程序设计(第三版)》
模式 | 样例 | 结果 | 关键属性/概念 | 方法 | 缺点 | 备注 |
工厂模式 |
function createPerson(name, age, job){ var o = new Object(); o.name = name; o.age = age; o.job = job; o.sayName = function(){ alert(this.name); }; return o; } var person1 = createPerson(“Nicholas”, 29, “Software Engineer”); //函数调用 var person2 = createPerson(“Greg”, 27, “Doctor”);
|
包含三个属性一个方法的对象,返回的是同一实例 | 对象无法识别,即返回的是同一对象 | |||
构造函数模式 |
function Person(name, age, job){ this.name = name; this.age = age; this.job = job; this.sayName = function(){ alert(this.name); }; //每定义一个函数,就是实例化了一个对象! //逻辑上等同于: this.sayName = new function(){}; } var person1 = new Person(“Nicholas”, 29, “Software Engineer”); var person2 = new Person(“Greg”, 27, “Doctor”);
|
person1、person2分别保存Person不同实例 | constructor:指向Person;是共享的 | 每个方法都要在每个实例上重新创建一遍 | 1.构造函数适中以大写字母开头; 2.构造函数本身也是函数,只不过可以用来创建对象; 3.必须使用new,否则跟普通函数没有区别; 4.不使用new,this对象会指向window |
|
构造函数模式2 |
function Person(name, age, job){ this.name = name; this.age = age; this.job = job; this.sayName = sayName; } function sayName(){ alert(this.name); } var person1 = new Person(“Nicholas”, 29, “Software Engineer”); var person2 = new Person(“Greg”, 27, “Doctor”);
|
同上 | 同上 | 全局作用域中的函数实际上只被某个对象调用了,杀鸡焉用宰牛刀?! | 方法sayName()从构造函数中拿出来了。 | |
原型模式 |
function Person(){ } Person.prototype.name = “Nicholas”; Person.prototype.age = 29; Person.prototype.job = “Software Engineer”; Person.prototype.sayName = function(){ alert(this.name); }; /****更简单的原型语法,此时上下文顺序不可变********** 此时constructor不指向Person,默认指向Object构造函数 Person.prototype = { constructor : Person, //须手动指向constructor name : "Nicholas", age : 29, job : “Software Engineer”, sayName : function () {alert(this.name);} }; **************************************************/ var person1 = new Person(); person1.sayName(); //”Nicholas” var person2 = new Person(); person2.sayName(); //”Nicholas” alert(person1.sayName == person2.sayName); //true
|
新对象的属性和方法由所有实例共享 | prototype:原型指针,指向对象(通过调用构造函数而创建的那个对象实例的原型对象,即Person Prototype) | 关系检测方法:isPrototypeOf(); 获得值: getPrototypeOf(); 检测属性属于实例: hasOwnProperty(); 检测属性存在: in; 得到全部实例属性: getOwnPropertyNames(); |
包含引用类型值的属性 共享,如String、Array、Object等 | 1.创建的每个函数都有一个prototype属性; 2.[[prototype]]指向Person.prototype; 3.不能通过对象实例重写原型中的值 |
组合使用构造函数模式和原型模式 |
function Person(name, age, job){ //属性 this.name = name; this.age = age; this.job = job; this.friends = [“Shelby”, “Court”]; } Person.prototype = { //方法、共享属性用原型 constructor: Person, sayName : function () {alert(this.name);} }; var person1 = new Person(“Nicholas”, 29, “Software Engineer”); var person2 = new Person(“Greg”, 27, “Doctor”); person1.friends.push(“Van”); alert(person1.friends); //”Shelby,Court,Van” alert(person2.friends); //”Shelby,Court” alert(person1.friends === person2.friends); //false alert(person1.sayName === person2.sayName); //true
|
1.构造函数模式用于定义实例属性,原型模式用于定义方法和共享的属性。 2.目前在ECMAScript中使用最广泛、认同度最高的;用来定义引用类型的一种默认模式。 |
||||
动态原型模式 |
function Person(name, age, job){ //properties this.name = name; this.age = age; this.job = job; //methods if (typeof this.sayName != “function”){ Person.prototype.sayName = function(){ alert(this.name); }; } } var friend = new Person(“Nicholas”, 29, “Software Engineer”); friend.sayName();
|
所有信息都封装在构造函数中,通过在构造函数中初始化原型;即 通过检查某个应该存在的方法是否有效来决定是否需要初始化原型。 | ||||
寄生构造函数模式 |
function Person(name, age, job){ var o = new Object(); o.name = name; o.age = age; o.job = job; o.sayName = function(){alert(this.name);}; return o; } var friend = new Person(“Nicholas”, 29, “Software Engineer”); //调用与工厂模式有区别 friend.sayName(); //”Nicholas”
|
1.除用new以外,其他跟工厂模式一样; 2.构造函数返回的对象与在构造函数外部创建的对象没有不同。所以,不能依赖instanceof操作符确定对象类型。 3.尽量不使用这种方式。 |
||||
稳妥构造函数模式 |
function Person(name, age, job){ //创建要返回的对象 var o = new Object(); //可以在这里定义私有变量和函数 //添加方法 o.sayName = function(){ alert(name); }; //返回对象 return o; } var friend = Person("Nidcholas", 29, "Software Engineer"); friend.sayName(); //"Nicholas"
|
1.除非使用 sayName()方法,没有其他方法访问name的值 2.不可能有别的方法访问传入到构造函数中的原始数据 |
稳妥对象: 没有公共属性、且其方法不引用this的对象 | 1.适用于安全环境(禁止this和new); 2.遵循与计生构造函数类似的模式,但不用this和new; 3.安全执行环境举例:Adsafe、Caja; 4.同上第2条。 |
||
附注:复制代码做测试时,注意有些双引号为中文模式,需修改为英文模式。 |