工厂模式创建对象
这种方式是为了解决实例化对象产生的大量重复的问题。采用这种方法可以集中地创造多个对象
function createObject(name,age) {
var obj=new Object();
obj.name=name;
obj.age=age;
obj.run=function () {
return this.age+this.name;
}
return obj;
}
var bb= createObject("sasa",13);
var cc=createObject("dddd",24);
console.log(bb.run());
console.log(cc.run());
console.log(bb instanceof Object); //true
console.log(bb instanceof createObject); //false
但是这这种方式创建起来的对象分不清是属于谁创建起来的
所以采用下面的这种方式
构造函数的方法来创建对象
所有构造函数的对象都是Object()
注意:
构造函数首字母要大写
1、构造函数没有new Object()但是在new 的过程中会自动的调用new Object();
2、this就相当于obj
3、构造函数不需要返回对象引用,它是后台自动返回的
function Box(name,age) {
this.name=name;
this.age=age;
this.run=function () {
return this.name+this.age;
}
}
function Desk(name,age) {
this.name=name;
this.age=age;
this.run=function () {
return this.name+this.age;
}
}
var bb=new Box("sss",13);
var cc=new Desk("ddd",14);
console.log(bb.run()); //sss13
console.log(cc.run()); //ddd14
console.log(bb instanceof Box); //true
console.log(cc instanceof Box); //false
console.log(cc instanceof Desk); //true
对象冒充调用
function Box(name,age) {
this.name=name;
this.age=age;
this.run=function () {
return this.name+this.age;
}
}
var o=new Object();
Box.call(o,"sasa",13);
console.log(o.run()) //sasa13
使用o来冒充Box
构造函数中的方法,是存放在实例化后边的对象中的,每一个对象的都不一样
function Box(name,age) {
this.name=name;
this.age=age;
this.run=function () {
return this.name+this.age;
}
}
var bb=new Box("Lee",13);
var cc=new Box("Lee",13);
console.log(bb.age==cc.age); //true 比较的是值
console.log(bb.run()==cc.run()); //true 比较的是对象调用run方法以后的返回值是否相等。
console.log(bb.run==cc.run); //false 比较的是地址,因为是两个对象的方法,所以对象的地址肯定是不一样的
但是可以把构造函数里的某个方法绑定到同一个函数来保证他们引用的地址是相同的。
function Box(name,age) {
this.name=name;
this.age=age;
this.run=run; //绑定到一个外部函数,但是外部也可以调用了
}
function run() {
return this.name+this.age;
}
var bb=new Box("Lee",13);
var cc=new Box("Lee",13);
console.log(bb.age==cc.age); //true 比较的是值
console.log(bb.run()==cc.run()); //true 比较的是对象调用run方法以后的返回值是否相等。
console.log(bb.run==cc.run); //true
上面的这种方法是不提倡的。最好的方法是把这个对象的所有的方法和属性绑定起来,。
原型
创建的每一个函数都有一个prototype,这个属性就是一个对象。它的用途是包含可以由特定类型的所有实例共享的属性和方法。 prototype通过调用构造函数而创建的那个对象的原型对象,使用原型的好处是可以让所有的对象共享它所包含的属性和方法。
function Box() {
}
Box.prototype.name="zhao";
Box.prototype.run=function () {
return rhis.name;
}
var bb=new Box();
var cc=new Box();
console.log(bb.run==cc.run); //true
上面的例子显示的是,原型中的属性和方法都是共享的
只有函数由prototype属性由函数new 出来的对象没有prototype属性
prototype里边还有两个属性,这两个属性是创建对象的时候生成的:
1、proto这个属性的是实例指向原型对象的一个指针
2、constructor 通过这个属性和方法可以访问到构造函数
判断一个对象是否指向了原型对象,基本上只要实例化了,就会自动的指向这个源性对象
实例中的同名属性会覆盖原型中的同名属性。
如何判断这个属性是在构造函数里边还是在原型里边。
判对象的属性是在原型中还是构造函数中
hasOwnProperty这个函数可以判断某一个属性是否在实例中还是原型中
in这个函数判断的属性只要在原型和实例中都有
function Box(age) {
this.age=age;
}
Box.prototype.name="zhao";
Box.prototype.run=function () {
return rhis.name;
}
var bb=new Box(12);
var cc=new Box(13);
console.log(bb.hasOwnProperty("name")); //true
console.log(bb.hasOwnProperty("age")); //true
console.log("age" in bb); //true
可以利用hasOwnProperty这个函数判断某一个属性是否是属于构造函数的,通过封装isPrototype来判断某一个属性来判断某一个属性是否属于原型
利用in和hasOwnProperty这个两个属性来封装一个函数,函数的功能就是判断某一个属性是不是对象原型 isPrototype
function isPrototype(prototype,object) {
return !object.hasOwnProperty(prototype)&&(prototype in object);
}
function Box(age) {
this.age=age;
}
Box.prototype.name="zhao";
Box.prototype.run=function () {
return this.name;
}
var bb=new Box(13);
console.log(isPrototype('name',bb)); //true
console.log(isPrototype('age',bb)); //false
以字面的方式创建对象的原型
使用对象的实例属性无法访问到prototype但是使用构造函数名来访问原型
function Box(age) {
this.age=age;
}
var bb=new Box(13);
console.log(bb.prototype); //undefined
必须通过proto来访问
原因是:
演示使用字面量的方式和使用构造函数来分别创建对象的不同
function Box(age) {
this.age=age;
}
var bb=new Box(13);
var mm={name:"sas"};
console.log(Box.prototype.constructor); //function Box(){}
console.log(mm.constructor) //function Object(){}
注意的是:
使用构造函数创建原型对象(上上面的例子)和使用字面量创建对象在使用基本相同,但是还是有一些区别,
1、使用构造函数创建原型对象(上上面的例子)会让constructor指向构造函数
2、使用字面量方式创建Prototype的方式会使得constructor属性指向Object()
所以使用字面量为原型再赋值的时候,首先让constructor指向u原来的构造函数
function Box(age) {
this.age=age;
}
Box.prototype.name="zhao";
Box.prototype.run=function () {
return this.name;
}
var bb=new Box(13);
console.log(bb.constructor); //Box(age) {this.age=age;}
上面的例子证明了1、
function Box(age) {
this.age=age;
}
Box.prototype={};
var bb=new Box(13);
console.log(bb.constructor); //Object() { [native code] }
上面的例子证明了2、
想要在使用字面的方式创建的prototype的constructor依然是指向构造哈函数的时候,可以这样使用
function Box(age) {
this.age=age;
}
Box.prototype={
constructor:Box
};
var bb=new Box(13);
console.log(bb.constructor); //Box(age) {this.age=age;}
这样就既体现了封装的效果也让原来的constructor指向了构造函数
使用字面量的方式创建的原型对象会切断原来的源性对象和构造函数之间的关系
function Box(age) {
this.age=age;
}
Box.prototype.name="zhao";
Box.prototype.run=function () {
return this.name;
}
Box.prototype={sex:"mm"};
var bb=new Box(13);
console.log(bb.name); //undefined
内置对象的原型
扩展内置对象的方法
String.prototype.addString=function (cc) {
return this+cc;
}
console.log("aa".addString("dsa")) //aadsa
原型模式创建对象的优点和缺点
原型模式省略了构造函数传参初始化的过程,带来的缺点就是初始化的过程中所有的初始值都是一样的,所以它最大的缺点就是共享
原型中所有属性都是共享的,共享对于函数非常合适,但是对于引用类型旧是不可以的,
演示原型的缺点
function Box() {}
Box.prototype= {
construstor:Box,
family: ["sasa", "das"]
}
var cc=new Box();
var dd=new Box();
cc.family.push("sas");
console.log(cc.family); //["sasa", "das", "sas"]
console.log(dd.family); //都被修改成了 ["sasa", "das", "sas"]
所以一般的解决方法就是 构造函数+原型模式
构造函数中使用的是每一个实例中都不能共享的属性
原型模式中保存的是 每一个实例可以共享的属性和函数
function Box(age) {
this.family=["sasa", "das"];
this.age=age;
}
Box.prototype= {
construstor:Box,
run:function () {
return this.age
}
}
var cc=new Box(13);
var dd=new Box(14);
cc.family.push("sas");
console.log(cc.run()); //13
console.log(cc.family) //["sasa", "das", "sas"]
console.log(dd.run()); //14
console.log(dd.family) //["sasa", "das"]
但是上面这种模式没有很好的体现封装性,所以应该使用动态的原型模式
function Box(age) {
this.family=["sasa", "das"];
this.age=age;
if(typeof this.run!="function"){
Box.prototype.run=function () {
return this.age;
}
}
}
var cc=new Box(13);
console.log(cc.run());
使用动态原型的模式创建的对象
继承
使用对象原型链继承
function Box() {
this.name="Lee";
}
function Desk() {
this.age=100;
}
Desk.prototype=new Box();
var desk=new Desk();
console.log(desk.name);
console.log(desk.age);
function Table() {
this.level="AAAA";
}
var table=new Table();
console.log(table.level);
使用对象冒充继承
但是这种继承方式不能继承原型里边的方法,只能继承构造函数里边的属性和方法
function Box(age) {
this.name="Lee";
this.age=age;
}
Box.prototype.run=function () {
return 11;
}
function Desk(age) {
Box.call(this,age); //借用了Box的构造函数
}
var desk=new Desk(12);
console.log(desk.age);
console.log(desk.run());
程序运行的时候会提醒没有定义run()方法