Object
的实例,添加属性和方法:var animal = new Object(); animal.name = "Kara the puppy"; animal.age = 2; animal.sayName = function(){ alert(this.name); }
或者用对象字面量的方式:
var animal = { name:"Kara the puppy", age:2, sayName:function(){ alert(this.name); } }
缺点:① 产生大量重复代码。② 即使使用的字面量相同,每次使用字面量时,JavaScript都会创建一个全新的对象:
var x = {a:18, b:28}; var y = {a:18, b:28}; console.log(x === y);//false
于是有了工厂模式。
1. 工厂模式
function createAnimal(name, age){ var animal = new Object(); animal.name = name; animal.age = age; animal.sayName = function(){ alert(this.name); }; return animal; } var Animal1 = createAnimal("kara",2); var Animal2 = createAnimal("Oto",3);
工厂模式创建的函数被多次调用,通过这种方式来创建类似对象。
缺点:①无法确定对象的类型(因为都是Object)。
②创建的多个对象之间没有关联。
2.构造函数模式
function Animal(name, age){ this.name = name; this.age = age; this.sayName = function(){ alert(this.name); } } var Animal1 =new Animal("kara",2); var Animal2 =new Animal("Oto",3);
构造函数始终都应该以一个大写字母开头,以区别其他类型的函数。新创建的两个实例都拥有 constructor 属性,
缺点:多个实例重复创建同名方法,但不是同一个方法,无法共享。多个实例都有sayName方法,但均不是同一个Function的实例:
console.log(Animal1.sayName === Animal2.sayName); //false
3.原型方法
使用原型对象的实例就是让所有实例共享它所包含的属性和方法。
function Animal(){ } Animal.prototype.name = "kara"; Animal.prototype.age = 2; Animal.prototype.sayName = function(){ alert(this.name); }; var Animal1 = new Animal(); Animal1.sayName(); //"kara" var Animal2 = new Animal(); Animal2.sayName(); //"kara" console.log(Animal1.sayName === Animal2.sayName); //true
缺点:①无法传入参数,不能初始化属性值。
②如果包含引用类型的值时,改变其中一个实例的值,则会在所有实例中体现。
4. 组合使用构造函数模式和原型模式
function Animal(name, age){ this.name = name; this.age = age; } Animal.prototype.sayName = function(){ alert(this.name); } var Animal1 = new Animal('Kara', '2'); var Animal2 = new Animal('Oto', '3');
优点:构造函数定义实例属性,原型共享方法和想要共享的属性。可传递参数,初始化属性值。
5.动态原型模式
通过检查某个应该存在的方法是否有效,来决定是否要初始化原型。
function Animal(name, age){ this.name = name; this.age = age; if(typeof this.sayName !== 'function'){ Animal.prototype.sayName = function(){ alert(this.name); } } } var Animal1 = new Animal('Kara', '2'); var Animal2 = new Animal('Oto', '3');
if语句中只会调用一次,就是在碰到第一个实例调用方法时会执。此后所有实例都会共享该方法。在动态原型方法下,不能使用对象字面量重写原型。
6.寄生构造函数模式
寄生构造函数模式和工厂模式没有本质区别,通过new 操作符的就叫寄生构造函数模式,直接调用的就叫工厂模式:
function createAnimal(name, age){ var animal = new Object(); animal.name = name; animal.age = age; animal.sayName = function(){ alert(this.name); }; return animal; } var Animal1 = new createAnimal("kara",2); var Animal2 = new createAnimal("Oto",3);
在不改变原有构造函数的前提下为构造函数添加特殊的方法,(不在原型上定义新的方法,是因为修改了Array的prototype,所有Array实例都会继承这样一个方法,得不偿失)
这个构造函数的功能就是传入参数,生成一个数组对象,
并且这个数组扩展了一个 toPipedString 方法,并不影响全局构造函数:
function SpecialArray(){ //创建数组 var values = new Array(); //添加值 values.push.apply(values,arguments); //添加方法 values.toPipedString = function(){ return this.join("|"); } //返回数组 return values; } var colors = new SpecialArray("red","blue","green"); console.log(colors.toPipedString()); //red|blue|green
寄生构造函数模式返回的对象与构造函数或者构造函数的原型没有任何关系。也就是说,构造函数返回的对象与在构造函数外部创建的对象没有什么不同。为此,不能依赖instanceof
操作符来确定对象的类型。
7. 稳妥构造函数模式
function Person(name, age, job) { var o = new Object(); // private members 定义私有变量和函数 var nameUC = name.toUpperCase(); // public members 公共变量和函数 o.sayName = function() { alert(name); }; o.sayNameUC = function() { alert(nameUC); }; return o; } var person = Person("Nicholas", 32, "software Engineer"); person.sayName(); // "Nicholas" person.sayNameUC(); // "NICHOLAS" alert(person.name); // undefined alert(person.nameUC); // undefined
所谓稳妥对象,是指没有公共属性,而且其方法也不引用this
对象。稳妥对象最适合在一些安全环境中(这些环境会禁止使用this
和new
),或者在防止数据被其他应用程序改动时使用。
稳妥构造函数遵循的与寄生构造函数类似的模式,但又两点不同:一是新创建对象的实例方法不引用this
;二是不使用new
操作符调用构造函数。
以这种模式创建的对象,只能通过 sayName()
方法访问name
的值。