javascript创建类的7种方式
一 使用字面量创建
1.1 示例
var obj={};
1.2 使用场景
比较适用于临时构建一个对象,且不关注该对象的类型,只用于临时封装一次数据,且不适合代码重用所以临时使用下就显得很方便,与C#相比就不用先定义一个类然后实例化对类的属性进行读写操作
常见于事件数据封装,向服务器提交数据封装等等
二 工厂模式
2.1 示例
function createPerson(name,sex){
var obj={};
obj.name=name;
obj.sex=sex;
return obj;
};
2.2 适用场景
较之字面量创建模式来说,工程模式可以传递参数构建对象,且代码能够复用,所以工厂模式适用于多次使用相同参数构建不同对象,例如创建ren对象,将需要的参数传入然后构建
2.3 优缺点
较之字面量创建模式来说,工厂模式有点在于代码复用,可以传递参数,但是不存在对象类型,不能用于构建复杂类型,属于小打小闹型,且也不能被其他类型继承。
三 构造模式
3.1 示例
function Person(name,age){
this.name=name;
this.age=age;
this.say=function(){
alert('speak chinese!');
}
}
3.1.1 使用new关键字
var p=new Person('zg',20);
3.1.2 直接像调用函数一样调用
如Person('zg',30)则本质上是,window.Person('zg',30);其内部this指针指向的window,在函数调用完毕后其内部的变量立即被回收所以没什么意义。
3.2 适用场景
构造模式可以使用参数构造对象,且能够使用typeof 测定其具体的类型,或者使用instanceof 测定是否为某个类型的实例,比较适合对象属性的封装
3.3 优缺点
优点:比工厂模式更加利于代码复用,且可以被继承,具有类型,能够使用typeof或instanceof检测,能够对多个属性进行封装,
缺点:构造模式中的方法实际上是对属性或者相关参数的逻辑处理,在每次创建对象时候都会在内存中存在,但是实际上这些方法是可以共用的,因此构造模式不利于内存利用
四 原型模式
4.1 原型
所谓原型其实是一个object即对象,这个对象是js面向对象编程的一种机制,他是js领域一切皆对象的一个基础,本质上是说任何一个对象皆有一个原型属性,即prototype,串联起来js中一切皆对象小到一个变量大到一个函数他们均会携带一个原型对象,比如var isMan=false,isMan.Prototype则是一个object,例如function Person(),他们都有一个原型对象。那么问题来了原型对象有什么用,既然他如此广泛的存在。
4.1.1 原型的由来
我们都知道所有类型都直接或者间接的继承自object,js中最原始也最神秘的对象,所有的类型原型均来自object的原型,不同之处在于他们在各自实例化的时候就想农家小院,每家每户或多或少都会有的私人区域,富裕的就大一些可以存放更多的函数,穷点的则只是继承祖上基业
4.1.2 原型用处
原型既然是对象,自然可以存储任何对象,但是在使用的时候我们一般把他用来存放对象方法
4.1.3 原型链
既然每个对象都有原型,那么一个对象继承一个对象,也可以访问起原型,这样串联起来就构成了原型链,就好像自己自然要继承父母那些财产,而自己呢也会有自己的私有财产,当我们的财产库得不到我们想要的东西我们再去问问父母那里有没有,举个例子比如有一天发现街上有专家在评鉴古董,自己家里没有,然后给父母打个电话问问家里头有啥古董没有,再如某一天自己家炒菜了发现没盐了,然后跑去父母那里问问还有盐没有,这种自己没有像上级搜索资源的机制叫做原型链
4.1.4 试探对象资源
in:如"name" in person1 :表示person1对象是否存在name属性,其查找路线,先查找对象是否拥有属性,然后查找对象原型是否拥有,然后再查找父类的原型是否拥有直到找到或者找到原型链顶端返回
hasOwnPrototype():如 hasOwnPrototype(‘name’) 直接在对象原型中查找是否拥有该属性,如果不存在继续向上级原型链查找
以上两种试探方式可以判定出属性或者方法是存在于实例还是原型中
for in
用于遍历对象内部的属性或者方法
如 for (var p in persion1)
alert(p);
4.1.4 示例
function Person(){}
Person.protorype={};
或者person.prototype.name=function(){}
person.prototype.sex=function(){}
person.prototype.setName=function(){}
4.2 适用场景
原型模式适用于一个类型只有方法,因为通过原型模式构建的对象,他们均共用一个原型,这在节约内存的同时也带来了不便
4.3 优缺点
原型模式优点在于对象共享原型对象,节约了内存,且原型包含一个construct该属性指向了构造函数,用于表示对象是由谁构造的,就相当于我们自己自然是父母构造的;
缺点在于原型最好只存储方法,因为原型是对象共享如果存储属性,则会导致一个对象修改了属性值影响其他对象对该值的控制,且原型没有构造一说所以也就丧失了构造的优势
4.4 原型在原生对象中应用
如object.prototype.toString=function(){}; Array.prototype.length=function(){}
同时原型对象可以直接在类型上进行扩展,如object.prototype.sayHello=function(){alert('hello')};
对象调用原型函数叫做对象方法,类型调用原型函数叫类型方法,类似于静态方法一说
五 组合构造模式和原型模式
5.1 组合思路
既然构造中原型对象是实例对象共享,构造利于属性封装,而原型模式利于方法封装,那么将两者组合使用自然相得益彰,因此组合构造和原型模式是非常常用且经典的定义类一种方式
5.2 示例
function Person(name){
this.name=name;
}
Person.prototype.say=function(){}
Person.prototype.walk=function(){}
以此类推,这种模式跟c#这样的强面向对象语言定义类的功能基本相当
5.3 优缺点
优点:兼并了构造和原型的优势
缺点:目前还没有明显的确定,如果拿去构建不复杂的类型,就是大材小用了
六 动态原型模式
6.1 示例
function Person(name){
this.name=name;
if(this.say!='function'){
Person.prototype.say=function(){}
}
}
6.2 使用场景
跟原型和组合模式相当
6.3 优缺点
优点:相对于原型模式来说比较保守,可以用于防止不小心覆盖父类中已经拥有该成员的情况
缺点:应该就是代码量多一点吧
七 寄生构造模式
7.1 示例
还记得工程模式吗?
function Person(name){
var obj=new {};
obj.name=name;
obj.say=function(){};
return obj;
}
如果 var p1=Person('sh');这叫工程模式
var p2 =new Person('re'); 这叫寄生模式
所谓寄生应该理解为在构建的obj上动态增加一些属性方法吧
7.2 适用场景
更工程模式类型吧,只不过是new出来的,该是工程模式的一种弥补
7.3 优缺点
相对于工程模式来说使用new构造对象,弥补了无法检测对象类型的问题
缺点呢:无法适用于复杂类型的定义