创建对象
创建方法
- new
let a = new Object();
a.name = "xiaoming";
console.log(a); // => {name: 'xiaoming'}
- {}
let b = {};
b.name = "dong";
console.log(b); // => { name: 'dong' }
创建模式
本质上只有上面两种方式创造对象,但是如果创建很多相同的对象用这种方法的话,会产生很多重复代码,所以需要有别的模式来创造很多对象。
let p1 = new Object();
p1.name = 'xiaohong';
p1.say = function(){
console.log("I am " + this.name);
}
p1.say();
当你需要创建很多个结构一样的对象都要这样复制一遍,那就太蛋疼了。所以去掉这些重复的代码就用到了工厂模式。
工厂模式
function createPerson(name){
let o = new Object();
o.name = name;
o.say = function(){
console.log("I am " + o.name);
}
return o;
}
let p1 = createPerson('xiaohong');
p1.say();
let p2 = createPerson('ming');
p2.say();
/*
I am xiaohong
I am ming
*/
这样改了之后创建对象就简单很多了,基本实现了代码复用。但是有个缺陷就是没办法识别不同类型的对象,只知道是Object对象。
构造函数模式
function Person(name){
this.name = name;
this.say = function(){
console.log("I am " + this.name);
}
/** 和上面函数逻辑是一样的
* this.say = new Function("console.log("I am " + this.name)")
*/
}
let p1 = new Person('hong');
p1.say();
let p2 = new Person('ming');
p2.say();
console.log(p1 instanceof Person);
console.log(p1.say == p2.say);
/*
I am hong
I am ming
true
false
*/
使用构造函数已经可以识别对象的类型了,每创建一个对象,属性和方法都会复制一份,对于属性每个对象都有一份挺正常的,但是没必要需要多份完成一样任务的方法。
原型模式
每个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。 既该构造函数的所有实例共享prototype里的内容。每创建一个函数,就会同时创建它的 prototype 对象,这个对象也会自动获得 constructor 属性
function Person(){
}
Person.prototype.name = 'hua';
Person.prototype.friends = ['gang', 'li'];
Person.prototype.say = function(){
console.log("I am " + this.name + " friends:" + this.friends);
}
let p1 = new Person();
p1.name = 'ming';
p1.friends.push('qiang');
let p2 = new Person();
p2.name = 'hong';
p2.friends.push('chen');
p1.say();
p2.say();
console.log(p1.say == p2.say);
/*
I am ming friends:gang,li,qiang,chen
I am hong friends:gang,li,qiang,chen
true
*/
p1和p2都有一个 __proto__
指向了Person的 prototype 对象,原型中所有属性是被很多实例共享的,这种共享对于函数非常合适。对于那些包含基本值的属性倒也说得过去,毕竟(如前面的例子所示),通过在实例上添加一个同名属性,可以隐藏原型中的对应属性。然而,对于包含引用类型值的属性来说,问题就比较突出了。
组合使用构造函数模式和原型模式
function Person(name){
this.name = name;
this.friends = ['gang', 'li'];
}
Person.prototype.say = function(){
console.log("I am " + this.name + " friends:" + this.friends);
}
let p1 = new Person('hong');
p1.friends.push('qiang');
let p2 = new Person('ming');
p2.friends.push('chen');
p1.say();
p2.say();
/*
I am hong friends:gang,li,qiang
I am ming friends:gang,li,chen
*/
这样创建出来的每个对象都是独享属性,共享方法了。
继承
这个时候如果我想新创建一种对象Student,这个对象有Person所有的属性和方法,另外还有属于Student的新属性和方法,那么我要把Person的内容再复制一遍吗?这样明显没有做到代码复用,这个时候就要用到了prototype来实现继承了。