最近找实习,上一场电话面试突如起来,没有一点点防备。。。问了一些javascript的题目感觉答得渣渣渣,然后又捡起《javascript高级程序设计》开始复习javascript基础==
本节复习面向对象的程序设计,详细记录的创建对象的七种方式,从工厂模式到组合模式,从动态原型式到稳妥构造函数模式。
创建对象的最简单方式是使用对象字面量,或使用Object构造函数
var obj = {
name: "caesar",
age: 20,
showName: function() {
console.log(this.name);
}
}
使用这种方式创建对象很简单,但是存在一个问题:如果需要创建很多对象,这些对象的属性和方法相同,通过对象字面量和Object构造函数创建对象,无疑会有大量的重复代码。
为解决重复代码的问题,由此引入第一种创建对象的方法:工厂模式。
工厂模式
// 工厂模式
function createPerson(name,age) {
var obj = new Object();
obj.name = name;
obj.age = age;
obj.showName = function() {
console.log(this.name)
};
return obj;
}
var person1 = createPerson("haha",20);
person1.showName();
console.log(person1 instanceof Person);
console.log(person1.constructor == Person);
工厂模式很好理解,从名字理解就是作为一个生产对象的工厂来创建对象,因此去除了重复性的代码。
但是工厂模式同样存在一定的问题:对象是通过工厂创建的,无法知道对象的类型。由此引入下一个方法,构造函数模式。
构造函数模式
function Person(name,age) {
this.name = name;
this.age = age;
this.showName = function() {
console.log(name);
}
}
var person1 = new Person("caesar",20);
person1.showName();
console.log(person1 instanceof Person);
console.log(person1.constructor == Person);
任何函数通过new操作符调用都可以作为构造函数,不通过new调用那就是普通的函数,通过new创建实例,经历了以下四步:
1. 创建一个新对象
2. 将构造函数作用域赋给新对象
3. 执行构造函数中的代码
4. 返回新对象
通过构造函数模式解决了工厂模式存在的问题:不能识别对象类型。创建的实例有一个constructor属性,指向Person。当然,通过instanceof检测对象类型更靠谱。
构造函数模式同样存在一定问题:每个方法都会在每个实例上重现创建一遍,然而其实这些方法是可以公用的。
// 函数也是对象,每定义一个函数相当于实例化一个对象
this.showName = new Function("console.log(name)");
// 不同实例的同名函数是不相等的
var person1 = new Person("caesar",20);
var person2 = new Person("hahaha",22);
// 打印false
console.log(person1.showName == person2.showName);
为了解决这个问题,又引入了原型模式。
原型模式
function Person() {
}
Person.prototype.name = "caesar";
Person.prototype.age = 20;
Person.prototype.showName = function() {
console.log(this.name)
}
var person1 = new Person();
var person2 = new Person();
person1.showName();
// 打印true
console.log(person1.showName == person2.showName);
每个函数又一个prototype属性,prototype是一个指针,指向一个对象,该对象包含可以被某些类型的实例共享的属性和方法。使用原型对象可以让所有的实例共享原型对象的属性和方法,因而解决了在构造函数模式中存在的问题。
关于原型对象
暂略
原型模式要注意的几点
暂略。。。
原型模式同样也存在问题:
1.没有为构造函数传递参数,所有实例在默认情况下都将取得相同值。
2.最重要的问题是,原型中的属性和方法是共享的,这很不错,对于某些共享的方法和基本值的属性来说。但是对于引用类型的值来说,就存在严重的问题了。
function Person() {
}
Person.prototype.friends = ['aaa','bbb'];
var person1 = new Person();
var person2 = new Person();
person1.friends.push("ccc");
// 打印[ 'aaa', 'bbb', 'ccc' ]
console.log(person1.friends);
// 打印[ 'aaa', 'bbb', 'ccc' ]
console.log(person2.friends);
为了解决这个问题,又引入了下面的这个模式:组合模式
组合模式
组合使用原型模式和构造函数模式,集两种模式的优点,构造函数模式用来定义实例属性,原型模式用来定义共享属性。
function Person(name,age) {
this.name = name;
this.age = age;
this.friends = ["aaa"];
}
Person.prototype.showFriends = function() {
console.log(this.friends);
}
var person1 = new Person("caesar",19);
var person2 = new Person("hahaha",20);
person1.friends.push("bbb");
person1.showFriends();// [ 'aaa', 'bbb' ]
person2.showFriends();// [ 'aaa' ]
组合模式是使用最广泛的模式。
再坚持一下,还有3个模式要写==
动态原型模式
对于组合模式,可能会有人觉得困惑:构造函数和原型相互独立,感觉怪怪得?
为解决这种困惑,从而产生的动态原型模式:将所有信息封装在构造函数中。在构造函数中初始化原型。
function Person(name,age) {
this.name = name;
this.age = age;
if(typeof this.showName != "function") {
Person.prototype.showName = function() {
console.log(this.name);
}
}
}
var person1 = new Person("caesar",20);
person1.showName();
比较容易理解,不解释。
寄生构造函数模式
function Person(name,age) {
var obj = new Object();
obj.name = name;
obj.age = age;
obj.showName = function() {
console.log(this.name);
}
return obj;
}
var person1 = new Person("caesar",20);
person1.showName();
顾名思义。。。创建对象的代码寄生在构造函数里面。。。
构造函数中返回的对象与构造函数和构造函数原型没有关系,因而无法确定对象类型。
但是这种模式在某些特殊情况下可以使用,但一般情况下尽量不要使用这种模式。
稳妥构造函数模式(安全模式)
与寄生构造函数模式类似,但是有两点不同:
1.新创建对象的实例方法不引用this
2.不使用new操作符调用构造函数
function Person(name,age) {
var obj = new Object();
obj.showName = function() {
console.log(name);
}
return obj;
}
var person1 = Person("caesar",20);
person1.showName();
除了调用showName方法之外没有办法再访问原始数据成员。
这种安全模式适用于某些安全环境。