工厂模式
function createPerson(name ,age ,job){
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function(){
console.log(this.name);
}
return o;
}
- 虽然解决了创建多个相似对象的问题,但是没有解决对象识别的问题(即怎样知道一个对象的类型)。
构造函数模式
function Person(name, age ,job){
this.name = name ;
this.age = age;
this.job = job;
this.sayName = function(){
console.log(this.name);
}
}
var person1 = new Person("kaifa",21,"Boss");
console.log(person1 instanceof Person); //true
console.log(person1 instanceof Object); //true
- 按照惯例,构造函数始终都应该以一个大写字母开头。
- 可以使用instanceof检测对象类型。
- 多种使用方式
//当做普通函数调用
Person("FAFA",22,"Manager");
window.sayName();
//在另一个对象的作用域中调用
var o = new Object();
Person.call(o ,"HAO",23,"Chairman");
o.sayName();
- 使用构造函数的主要问题,就是每个方法都要在每个实例上重新创建一遍。可以把函数定义转移到构造函数外部,但是这样自定义的引用类型就丝毫没有封装性可言了。这种方式创建的函数,会导致不同的作用域链和标识符解析。
function Person(name, age ,job){
this.name = name ;
this.age = age;
this.job = job;
//在逻辑上与声明函数是等价的
this.sayName = new Function("console.log(this.name)");
}
var person1 = new Person("kaifa",21,"Boss");
var person2 = new Person("kaifa",21,"Boss");
console.log(person1.sayName == person2.sayName);//false
原型模式
function Person(){
}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
console.log(this.name);
}
var person1 = new Person();
var person2 = new Person();
个对象之间的关系:
只要创建一个新函数,就会根据一组特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象。在默认情况下所有原型对象都会自动获得一个constructor(构造函数)属性,这个属性是一个指向prototype属性所在函数的指针。Person.prototype.constructor指向Person。
当用构造函数创建一个新实例后,该实例内部的将包含一个指针[[Prototype]],指向构造函数的原型对象。虽然在脚本中没有标准的方法来访问[[Prototype]],但Firefox,Safari,Chrome在每个对象上都支持一个属性_proto_。
- 判断对象之间的关系
Person.prototype.isPrototypeOf(person1);//true
Object.getPrototypeOf(person1) == Person.prototype;//true
person1.__proto__ == Person.prototype;//true
- 原型的动态性:每当代码读取某个对象的某个属性时,都会执行一次搜索,搜索首先从对象实例本身开始,如果实例中找到了具有给定名字的属性,则返回,否则继续搜索原型指针指向的原型对象。当修改了原型中的值,所有的实例对象都受到影响。
var person1 = new Person();
person1.name = "kaifa";
console.log(person1.name);
delete person1.name;
console.log(person1.name);
- 原型对象的问题:当原型中包含引用类型时,如果我们的初衷就是共享一个数组,那没问题,可实例一般来讲都是要有属于自己的所有属性。
function Person() {
}
Person.prototype = {
constructor: Person,
name: "Nicholas",
age: 29,
job: "Software Engineer",
friends: ["Shelby", "Court"],
sayName: function () {
console.log(this.name);
}
}
var person1 = new Person();
var person2 = new Person();
person1.friends.push("fafa");
console.log(person1.friends);//["Shelby", "Court","fafa"]
console.log(person2.friends);//["Shelby", "Court","fafa"]
- 判断属性存在于实例中,还是存在于原型中
hasOwnProperty():判断该对象中是否含有属性。
in:判断是否能够访问。
person1.hasOwnProperty("name");//false
person1.name = "fafa";
person1.hasOwnProperty("name");//true
"name" in person1;//true
delete person1.name;
"name" in person1;//true
delete person1._proto_.name;
"name" in person1;//false
构造函数和原型组合使用
function Person(name ,age ,job) {
this.name = name;
this.age = age;
this.job = job;
this.friends = ["Shelby", "Court"];
}
Person.prototype = {
constructor: Person,
sayName: function () {
console.log(this.name);
}
};