每天一篇javascript学习小结(面向对象编程)
1、面向对象的工厂方法
functioncreatePerson(name,age,job){ varo=newObject(); o.name=name; o.age=age; o.job=job; o.sayName=function(){ alert(this.name); }; returno; } varperson1=createPerson("Nicholas",29,"SoftwareEngineer"); varperson2=createPerson("Greg",27,"Doctor"); person1.sayName();//"Nicholas" person2.sayName();//"Greg"
工厂模型的方法的缺点是会产生大量重复代码!
2、构造函数模式创建对象
functionPerson(name,age,job){ this.name=name; this.age=age; this.job=job; this.sayName=function(){ alert(this.name); }; } varperson1=newPerson("Nicholas",29,"SoftwareEngineer"); varperson2=newPerson("Greg",27,"Doctor"); person1.sayName();//"Nicholas" person2.sayName();//"Greg" alert(person1instanceofObject);//true alert(person1instanceofPerson);//true alert(person2instanceofObject);//true alert(person2instanceofPerson);//true alert(person1.constructor==Person);//true alert(person2.constructor==Person);//true alert(person1.sayName==person2.sayName);//false
使用new关键字创建对象会经历以下四个过程
- 1、创建一个新对象
- 2、将构造函数的作用域赋给一个新对象(因此this就指向了这个新对象)
- 3、执行构造函数的方法(为这个新对象赋值)
- 4、返回新对象
3、将构造函数当函数用
functionPerson(name,age,job){ this.name=name; this.age=age; this.job=job; this.sayName=function(){ alert(this.name); }; } varperson=newPerson("Nicholas",29,"SoftwareEngineer"); person.sayName();//"Nicholas" Person("Greg",27,"Doctor");//addstowindow window.sayName();//"Greg" varo=newObject(); Person.call(o,"Kristen",25,"Nurse"); o.sayName();//"Kristen"
构造函数当做函数使用就和普通的函数没有任何不同,它属于window对象下面添加的方法而已。由于构造函数创建的对象实际上是创建一个新对象,因此在本质上两者还是不一样的,还是分离的,他们的方法还是不一样的!
4、将共有的方法方法全局解决不一致的问题
functionPerson(name,age,job){ this.name=name; this.age=age; this.job=job; this.sayName=sayName; } functionsayName(){ alert(this.name); } varperson1=newPerson("Nicholas",29,"SoftwareEngineer"); varperson2=newPerson("Greg",27,"Doctor"); person1.sayName();//"Nicholas" person2.sayName();//"Greg" alert(person1instanceofObject);//true alert(person1instanceofPerson);//true alert(person2instanceofObject);//true alert(person2instanceofPerson);//true alert(person1.constructor==Person);//true alert(person2.constructor==Person);//true alert(person1.sayName==person2.sayName);//true
虽然上面的方法解决了一致的问题,但是定义的全局的方法本身属于window,那么局部和全局就没有分开!所以这个方法使用的并不多见!也不建议使用。
5、原型模式
我们创建的任何的一个函数都有一个原型对象,这个属性是一个指针,它指向一个对象,而这个对象的作用是可以有特定的类型的所有的实例共享的方法!
functionPerson(){ } Person.prototype.name="Nicholas"; Person.prototype.age=29; Person.prototype.job="SoftwareEngineer"; Person.prototype.sayName=function(){ alert(this.name); }; varperson1=newPerson(); person1.sayName();//"Nicholas" varperson2=newPerson(); person2.sayName();//"Nicholas" alert(person1.sayName==person2.sayName);//true alert(Person.prototype.isPrototypeOf(person1));//true alert(Person.prototype.isPrototypeOf(person2));//true //onlyworksifObject.getPrototypeOf()isavailable if(Object.getPrototypeOf){ alert(Object.getPrototypeOf(person1)==Person.prototype);//true alert(Object.getPrototypeOf(person1).name);//"Nicholas" }
理解原型
无论什么时候只要是创建了一个函数,就会创建一个原型属性,这个属性指向函数的原型对象。在默认的情况下,原型对象都会包含一个constructor(构造函数属性),这个属性包含一个指向prototype属性所在函数的指针!
属性读取的顺序
每当代码读取某个对象的属性时候,都会执行一次搜索,目标是具有给定名字的属性,搜索从对象的实例本身开始查找,如有则返回,没有则继续搜索该对象的原型链,直至搜索到原型链的最外层!
functionPerson(){ } Person.prototype.name="Nicholas"; Person.prototype.age=29; Person.prototype.job="SoftwareEngineer"; Person.prototype.sayName=function(){ alert(this.name); }; varperson1=newPerson(); varperson2=newPerson(); person1.name="Greg"; alert(person1.name);//"Greg"来自实例 alert(person2.name);//"Nicholas"来自原型
如果删除了这个元素的实例属性
functionPerson(){ } Person.prototype.name="Nicholas"; Person.prototype.age=29; Person.prototype.job="SoftwareEngineer"; Person.prototype.sayName=function(){ alert(this.name); }; varperson1=newPerson(); varperson2=newPerson(); person1.name="Greg"; alert(person1.name);//"Greg"?frominstance alert(person2.name);//"Nicholas"?fromprototype deleteperson1.name; alert(person1.name);//"Nicholas"-fromtheprototype
6、hasOwnProperty方法
这个方法可以检测一个属性是否存在于实例中,还是存在于原型中!hasOwnProperty是从Object继承来的,只要给定属性存在于对象实例中,才会返回true.
functionPerson(){ } Person.prototype.name="Nicholas"; Person.prototype.age=29; Person.prototype.job="SoftwareEngineer"; Person.prototype.sayName=function(){ alert(this.name); }; varperson1=newPerson(); varperson2=newPerson(); alert(person1.hasOwnProperty("name"));//false alert("name"inperson1);//true person1.name="Greg"; alert(person1.name);//"Greg"?frominstance alert(person1.hasOwnProperty("name"));//true alert("name"inperson1);//true alert(person2.name);//"Nicholas"?fromprototype alert(person2.hasOwnProperty("name"));//false alert("name"inperson2);//true deleteperson1.name; alert(person1.name);//"Nicholas"-fromtheprototype alert(person1.hasOwnProperty("name"));//false alert("name"inperson1);//true
7、Object.keys()可枚举属性方法
这个方法接收一个对象作为参数,返回一个包含所有可枚举属性的字符串数组
functionPerson(){ } Person.prototype.name="Nicholas"; Person.prototype.age=29; Person.prototype.job="SoftwareEngineer"; Person.prototype.sayName=function(){ alert(this.name); }; varkeys=Object.keys(Person.prototype); alert(keys);//"name,age,job,sayName" 如果想得到所有实例的属性,无论它是否可以枚举都可以使用这个方法来获取 functionPerson(){ } Person.prototype.name="Nicholas"; Person.prototype.age=29; Person.prototype.job="SoftwareEngineer"; Person.prototype.sayName=function(){ alert(this.name); }; varkeys=Object.getOwnPropertyNames(Person.prototype); alert(keys);//"constructor,name,age,job,sayName"
此方法高版本浏览器才支持
8、简单的原型写法
functionPerson(){ } Person.prototype={ name:"Nicholas", age:29, job:"SoftwareEngineer", sayName:function(){ alert(this.name); } }; varfriend=newPerson(); alert(friendinstanceofObject);//true alert(friendinstanceofPerson);//true alert(friend.constructor==Person);//false alert(friend.constructor==Object);//true
重写了原型就等于将默认的原型方法覆盖,那么同样的构造方法也会被重写,重写的构造方法指向了Object对象!而不是原来的对象Person
如果还是想指向之前的构造方法,可以显示的指定
functionPerson(){ } Person.prototype={ constructor:Person, name:"Nicholas", age:29, job:"SoftwareEngineer", sayName:function(){ alert(this.name); } }; varfriend=newPerson(); alert(friendinstanceofObject);//true alert(friendinstanceofPerson);//true alert(friend.constructor==Person);//true alert(friend.constructor==Object);//false
9、原型方法的动态添加
functionPerson(){ } Person.prototype={ constructor:Person, name:"Nicholas", age:29, job:"SoftwareEngineer", sayName:function(){ alert(this.name); } }; varfriend=newPerson(); Person.prototype.sayHi=function(){ alert("hi"); }; friend.sayHi();//"hi"?works!
10、原生对象的原型方法
alert(typeofArray.prototype.sort);//"function" alert(typeofString.prototype.substring);//"function" String.prototype.startsWith=function(text){//修改原生对象的原型方法 returnthis.indexOf(text)==0; }; varmsg="Helloworld!"; alert(msg.startsWith("Hello"));//true
11、组合使用构造函数和原型模式创建对象
//构造函数模式 functionPerson(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); } }; varperson1=newPerson("Nicholas",29,"SoftwareEngineer"); varperson2=newPerson("Greg",27,"Doctor"); person1.friends.push("Van"); alert(person1.friends);//"Shelby,Court,Van" alert(person2.friends);//"Shelby,Court" alert(person1.friends===person2.friends);//false alert(person1.sayName===person2.sayName);//true
12、动态原型模式
functionPerson(name,age,job){ //properties this.name=name; this.age=age; this.job=job; //methods if(typeofthis.sayName!="function"){ Person.prototype.sayName=function(){ alert(this.name); }; } } varfriend=newPerson("Nicholas",29,"SoftwareEngineer"); friend.sayName();
13、寄生构造函数模式
functionPerson(name,age,job){ varo=newObject();//依赖全局对象初始化一个对象,然后再返回这个对象 o.name=name; o.age=age; o.job=job; o.sayName=function(){ alert(this.name); }; returno; } varfriend=newPerson("Nicholas",29,"SoftwareEngineer"); friend.sayName();//"Nicholas" functionSpecialArray(){ //createthearray varvalues=newArray(); //addthevalues values.push.apply(values,arguments); //assignthemethod values.toPipedString=function(){ returnthis.join("|"); }; //returnit returnvalues; } varcolors=newSpecialArray("red","blue","green"); alert(colors.toPipedString());//"red|blue|green" alert(colorsinstanceofSpecialArray);
上诉方法有一点说明下,由于它是依赖外层对象来创建一个新对象,因此不能依赖instanceof方法来确定属性和方法的来源!它实际上和构造函数的没有关系!
14、稳妥构造函数模式
functionPerson(name,age,job){ varo=newObject(); o.sayName=function(){ alert(name); }; returno; } varfriend=Person("Nicholas",29,"SoftwareEngineer"); friend.sayName();//"Nicholas"
此方法不依赖任何newthis关键符!如果要访问对象的方法和属性,只能通过对象已经定义好的方法来获取!
15、继承
javascript实现继承是通过原型链来实现的
functionSuperType(){ this.property=true;//定义一个属性 } SuperType.prototype.getSuperValue=function(){//定义的原型方法 returnthis.property; }; functionSubType(){ this.subproperty=false; } //inheritfromSuperType SubType.prototype=newSuperType(); SubType.prototype.getSubValue=function(){ returnthis.subproperty; }; varinstance=newSubType(); alert(instance.getSuperValue());//true alert(instanceinstanceofObject);//true alert(instanceinstanceofSuperType);//true alert(instanceinstanceofSubType);//true alert(Object.prototype.isPrototypeOf(instance));//true alert(SuperType.prototype.isPrototypeOf(instance));//true alert(SubType.prototype.isPrototypeOf(instance));//true SubType继承SuperType的方法和属性,因此当instance可以直接调用SuperType的方法! functionSuperType(){ this.property=true; } SuperType.prototype.getSuperValue=function(){ returnthis.property; }; functionSubType(){ this.subproperty=false; } //inheritfromSuperType SubType.prototype=newSuperType(); //newmethod SubType.prototype.getSubValue=function(){ returnthis.subproperty; }; //overrideexistingmethod SubType.prototype.getSuperValue=function(){ returnfalse; }; varinstance=newSubType(); alert(instance.getSuperValue());//false
上面的例子说明,重写的原型会覆盖之前继承的原型,最后返回的往往不是预期的效果
functionSuperType(){ this.property=true; } SuperType.prototype.getSuperValue=function(){ returnthis.property; }; functionSubType(){ this.subproperty=false; } //inheritfromSuperType SubType.prototype=newSuperType(); //使用字面量添加的方法导致上面的方法失效了 SubType.prototype={ getSubValue:function(){ returnthis.subproperty; }, someOtherMethod:function(){ returnfalse; } }; varinstance=newSubType(); console.log(instance); alert(instance.getSuperValue());//error!
下面的例子也说明重写原型带来的风险
functionSuperType(){ this.colors=["red","blue","green"]; } functionSubType(){ } //inheritfromSuperType SubType.prototype=newSuperType(); varinstance1=newSubType(); instance1.colors.push("black"); alert(instance1.colors);//"red,blue,green,black" varinstance2=newSubType(); alert(instance2.colors);//"red,blue,green,black"
原型共享导致两个不同的对象调用的同一个数据
16、借用构造函数来实现继承
functionSuperType(){ this.colors=["red","blue","green"]; } functionSubType(){ //inheritfromSuperType SuperType.call(this); } varinstance1=newSubType(); instance1.colors.push("black"); alert(instance1.colors);//"red,blue,green,black" varinstance2=newSubType(); alert(instance2.colors);//"red,blue,green"
传递参数
functionSuperType(name){ this.name=name; } functionSubType(){ //inheritfromSuperTypepassinginanargument SuperType.call(this,"Nicholas"); //instanceproperty this.age=29; } varinstance=newSubType(); alert(instance.name);//"Nicholas"; alert(instance.age);//29
17、组合继承方式
functionSuperType(name){ this.name=name; this.colors=["red","blue","green"]; } SuperType.prototype.sayName=function(){ alert(this.name); }; functionSubType(name,age){ SuperType.call(this,name); this.age=age; }
18、原型继承
functionobject(o){ functionF(){} F.prototype=o; returnnewF(); } varperson={ name:"Nicholas", friends:["Shelby","Court","Van"] }; varanotherPerson=object(person); anotherPerson.name="Greg"; anotherPerson.friends.push("Rob");
19、寄生组合式继承
functionobject(o){ functionF(){} F.prototype=o; returnnewF(); } functioninheritPrototype(subType,superType){ varprototype=object(superType.prototype);//createobject prototype.constructor=subType;//augmentobject subType.prototype=prototype;//assignobject } functionSuperType(name){ this.name=name; this.colors=["red","blue","green"]; } SuperType.prototype.sayName=function(){ alert(this.name); }; functionSubType(name,age){ SuperType.call(this,name); this.age=age; } inheritPrototype(SubType,SuperType); SubType.prototype.sayAge=function(){ alert(this.age); }; varinstance1=newSubType("Nicholas",29); instance1.colors.push("black"); alert(instance1.colors);//"red,blue,green,black" instance1.sayName();//"Nicholas"; instance1.sayAge();//29 varinstance2=newSubType("Greg",27); alert(instance2.colors);//"red,blue,green" instance2.sayName();//"Greg"; instance2.sayAge();//27
以上就是今天的javascript学习小结,之后每天还会继续更新,希望大家继续关注。