对象创建方法其实主要有两种最简单的方式:
- 创建一个Object实例
var person = new Object();
person.name = 'jinghong';
person.age = 22;
person.sayName = function(){
alert(this.name);
}
- 对象字面量
var person = {
name = ‘jinghong’,
age: ‘22’
}
一、工厂模式
function creatPerson(name, age, job){
var obj = new Object();
obj.name = name;
obj.age = age;
obj.job = job;
obj.sayName = function(){
alert(this.name);
}
return obj;
}
var person1 = createPerson('jinghong', 22, 'software engnieer');
var person2 = createPerson('tiantian', 21, 'teacher');
二、构造函数模式
//构造函数模式
function Person(){
this.name = name;
this.age = age;
this.job = job;
this.sayName = function(){
alert(this.name);
}
}
var person1 = new Person('jinghong', 22, 'software engnieer');
var person2 = new Person('tiantian', 21, 'teacher');
注意: 构造函数只是一些使用new 操作符时,被调用的普通函数,并不是一个类。任何函数被new调用时,它就是构造函数;
当一个函数被new表达式中被调用时,他是一个构造函数,他会初始化创建一个新的对象。
使用new来调用函数时会发生一下操作:
- 创建一个新的对象
- 将构造函数的作用域赋给这个对象(因此这个新对象会绑定到构造函数的this)
- 执行构造函数中的代码(为这个新的对象添加属性和方法)
- 返回新的对象
在前面的例子中,person1,person2分别是Person的实例;这两个实例对象都有一个constructor属性,该属性指向Person;
console.log(person1.constructor);//Person
console.log(person2.constructor);//Person
构造函数模式和工厂模式不同的地方是,可以将实例标识为一种特定的类型,
console.log(person1 intanceof Object); //true
console.log(person1 intanceof Person); //true
构造函数模式的缺点:
构造函数的每个实例中实际上都包含不同的Function实例,即:person1.sayName != person2.sayName
创建两个完成同样任务的Function实例的确没有必要,所以可以通过把函数定义转移到函数外面进行,来解决这个问题:
funtion Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = sayName;//一个函数的指针
}
function sayName(){
alert(this.name);
}
var person3 = new Person('person3', 21, 'doctor');
person3.sayName();//person3
三、原型模式
function Person(){
}
Person.prototype.name = 'jinghong';
Person.pertotype.age = 29;
Person.prototype.job = 'software Engineer';
Person.pertotype.sayName = funtion(){
alert(this.name);
}
var person1 = new Person();
var person2 = new Person();
person1.sayName();//'jinghong';
person2.sayName();//'jinghong'
构造函数为空函数,但是仍然可以通过new构造函数来创建一个新的对象,并且这些对象还会具有相同的属性和方法,但是与构造函数不同的是,新对象的属性和方法是所有实例共享的,所以person1和person2的sayName()方法是同一个函数;
什么是原型对象
在任何时候,只要创建一个新函数,就会根据一组特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象,原型对象在默认情况下拥有一个constructor属性,这个属性指向所在函数的指针,例如:Person.prototype.constructor指向person;
不能通过对象实例重写原型中的值
如果我们在实例中添加了一个属性,而属性与实例原型中的一个属性同名,那么我们就在实例中创建该属性,该属性会自动屏蔽原型中的那个属性。
简单的原型语法
function Person(){
}
Person.prototype{
name : 'jinghong',
age: 21,
sayName: function(){
alert(this.name);
}
}
原生对象的原型
通过給原生对象的原型对象添加或者修改方法,可以給基本包装类型添加或者修改方法;
例如:給基包装类型String添加名为startsWith()方法,检测一个字符串是否以某个特定的字符开始
String.prototype.stratWith = function(text){
return this.indexOf(text) == 0;
}
四、组合使用构造函数模式和原型模式
构造函数用于定义实例属性,原型模式用于定义方法和共享属性,这样所有实例都拥有自己的一份实例属性的副本,同时并拥有对共享方法的引用,最大限度的节省了内存
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.friends = ['a', 'b', 'c']
}
Person.prototype = {
constructor : Person;
sayName : function(){
alert(this.name);
}
var person1 = new Person('jinghong', 21, 'engineer');
var person2 = new Person('wenjuan', 21, 'engineer');
person1.friends.push('d');
console.log(person1.friends);//'a', 'b', 'c','d'
console.log(person2.friends);//'a', 'b', 'c'
console.log(person1.friends === person2.friends);//false
console.log(person1.sayName === person2.sayName);//true
五、动态原型模式
function Person(name, age, job){
//属性
this.name = name;
this.age = age;
this.job = job;
//方法
if (typeof this.name != 'function'){
Person.prototype.sayName = function(){
alert(this.name);
}
}
}
在上述代码中只有当以前的原型对象没有sayName方法时,才在原型链中添加sayName方法,并且这段代码只能在初次调用时才会执行,以后原型已经完成初始化,并且以后生成的实例都将具有修改后的sayName方法;