面向对象程序设计
工厂模式
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);
};
}
var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");
缺点: 每个方法都会被重新创建一遍,方法是可以被重用的,多次创建会造成资源浪费
原型模式
function Person(){ }
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
alert(this.name);
};
var person1 = new Person(); person1.sayName(); //"Nicholas"
var person2 = new Person();
缺点: 属性值是引用类型的数值,如果修改属性值那么就会在所有的实例中反映出来
混合模式(原型 + 构造函数)
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");
注意:
- 属性值、对象使用构造函数,方法使用原型
- 原型直接赋值,会覆盖默认原型,对应的将
construtor
属性覆盖,如果需要此属性,需要手动赋值
对象知识点
- 每个函数都有原型,
prototype
属性指向原型 - 每个原型对象都有一个
constructor
指向构造函数本身 - 每一个构造函数实例化对象都有一个
__proto__
对象指向构造函数的原型对象:prototype
-
delete
只能删除实例上的属性,不能删除原型上的属性 -
给实例属性名赋新值,只是创建在实例上覆盖了原型的值,不会修改原型上的值
var Person = function(){}; Person.prototype.name = 'wang'; var person1 = new Person(); person1.name = 'li'; console.log(person1.name); // li 只是覆盖了原型上的值,不能修改
-
isPrototypeOf
和getPrototypeOf
方法都可以判断实例化对象的原型Person.prototype.isPrototypeOf(person1); // true Object.getPrototypeOf(person1) === Person.prototype; // true
hasOwnProperty
和 in
区别
-
hasOwnProperty
如果属性在实例上那么返回true
,如果是原型上那么返回false
-
in
属性只要是可以访问到,那么就返回true
,不管是实例上还是原型上
var person1 = new Person();
var person2 = new Person();
person1.name = 'zhang';
person1.hasOwnProperty('name'); // true
person2.hasOwnProperty('name'); // false
'name' in person1; // true
'name' in person2; // false
Object.getOwnPropertyNames
和 Object.keys
比较
相同点
- 都可以用来获取对象的属性名,都不能获取原型上的对象
#### 不同点
-
getOwnPropertyNames
可以获取不可枚举属性,但keys
不能
面向对象的程序设计
- 工厂函数
- 构造函数
- 原型设计
- 原型 + 构造函数
确定原型和实例的关系
-
instanceof
和isPrototypeOf
都可以用来判断原型和实例的关系,且有一个共同点,只要是出现在原型链上的构造函数,都可以返回true
person1 instanceof Person; // true
person1 instanceof Object; // true
Person.prototype.isPrototypeOf(person1); // true
Object.prototype.isPrototypeOf(person1); // true
所有构造函数的原型默认是Object
的实例
继承
原型链
通俗的说就是一个构造函数的原型引用了另一个构造函数的实例,而引用的构造函数原型又引用了其他构造函数实例....,层层引用,形成一个引用链条
优点
- 可以很好实现继承,定义一次,可以复用
缺点
- 层层递进会形成共用属性,一个实例修改,那么所有引用会全部修改
- 创建子类型的实例时,不能给超类型构造函数传递参数
借用构造函数
通过call
或者apply
方法将一构造函数属性复用为自己的属性
var Person = function(){
this.name = 'wang';
}
var Child = function(){
Person.call(this);
this.age = 23;
}
var child = new Child();
child.hasOwnProperty('name'); // true 是对象的自有属性,而不是继承自原型链
优点
- 可以给超类型传参数
- 可以解决共享属性问题
缺点
- 不可见借用构造函数原型上的方法
- 无法复用函数,每实例化一个对象,就会创建一个函数,造成资源浪费
组合继承(最常用)
- 使用构造函数继承属性值
- 使用原型链继承原型上的属性和方法
Person.prototype.getName = function(){};
var Child = function() {
Person.call(this);
this.sex = 'female';
}
Child.prototype = new Person();
Child.prototype.getSex = function(){};
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。