标签:
hello,everybody,今天要探讨的问题是JS面向对象,其实面向对象呢呢,一般是在大型项目上会采用,不过了解它对我们理解JS语言是很大的意义。
首先什么是面向对象编程(oop),就是用对象的思想去写代码,那什么是对象呢,其实我们一直在用,像数组 Array 时间 Date 都是对象,并且这些对象是系统创建的,所以叫系统对象,而我们自己当然也可以创建对象,一般对象有两部分组成:
1 方法 (动态的 对象下面的函数)比如Array 的push(),sort()方法
2 属性 (静态的,相当于对象下面的变量)Array的 length属性
OK,既然存在面向对象的编程,那么一定有它的优点,那么我们来看看它的四大特点:
抽象:抓住核心问题
封装:只能通过对象来访问方法
继承:从已有对象上继承出新的对象
多态:多对象的不同形态
这些特点呢,一开始理解是比较抽象的,只有我们在实践起来更能理解它的意义。不过我们做简单的介绍。
抽象:我们知道呢,不同的对象下面的方法是不一样的,比如数组有属于数组的方法属性,时间对象有属于它的方法属性,我们不能把时间对象的方法加给数组,把很多的方法分门别类,放到不同的对象下面,就是一种抽象,更好的管理。
封装:这个就比较好理解了,就是每个方法必须得在指定的对象下用。
继承:假如我们有两个弹窗,第二个弹窗相比第一个弹窗仅仅是多了一个功能,这个时候,就适合用继承,第二个可以继承第一个的功能,然后在这基础上再增加功能,继承提高了我们对代码的复用。
多态:也是代码复用的一种形式,用的不太多,比如有一个电脑,我们只用一个接口,然后连接不同的设备,这些设备可以实现不同的功能。听起来比较抽象,一般后端语言用的比较多。
下面我们来具体看面向对象的创建以及创建模式的演变
1 创建一个面向对象
//创建一个面向对象 var obj = new Object(); //创建一个空对象 obj.name = ‘haha‘; obj.showName = function(){ alert(obj.name);
}
obj.showName();
这个栗子很简单,存在的问题是,当我们有多个面向对象的时候,重复代码过多,需要封装,所以有了下面的方法
2 工厂方式
function CreatePerson(name){ //原料 var obj = new Object(); //加工 obj.name = name; obj.showName = function(){ alert(this.name); } //出厂 return obj; } var p1 = CreatePerson(‘haha‘); p1.showName(); var p2 = CreatePerson(‘hehe‘); p2.showName();
这其实就是简单的封装函数,整个过程像工厂的流水线,所以叫工厂方式,但为了与我们的系统对象(Array等)保持一致,所以我们要进行改造,成为构造函数模式
3 构造函数模式
我们要通过这三个方面来改变:1 函数名首字母大写 2 New 关键字提取 3 this指向为新创建的对象
function CreatePerson(name){ //函数名首字母大写 //var this=new Object(); //系统偷偷替咱们做:不用写
this.name = name;
this.showName = function(){
alert(this.name);
}
//return this;//而且函数的默认返回值就是this即这个对象(隐式返回 不用自己再写返回值
}
var p1 =new CreatePerson(‘haha‘);
//当用new去调用一个函数:这个时候this指的就是创建出来的对象 而且函数的默认返回值就是this即这个对象(隐式返回 不用自己再写返回值)
p1.showName();
var p2 = new CreatePerson(‘hehe‘);
p2.showName();
所以最终的代码是这样的
function CreatePerson(name){ this.name = name; this.showName = function(){ alert(this.name); } } var p1 =new CreatePerson(‘haha‘); p1.showName(); var p2 = new CreatePerson(‘hehe‘); p2.showName();
但是函数构造模式也存在相应的问题:
alert(p1.showName==p2.showName);//false
测试这个代码,两个方法是不相同的,也就是说这两个对象并不是共用一个方法,每new一次,系统都会新创建一个内存,这两个对象各自有各自的地盘,但他们具有相同的功能,还不共用,肯定不是我们所希望的。所以就有了下一种方法,原型模式
4 原型模式
我们创建的每个函数都有原型(prototype),从字面意思看,就是指最原始的,原型是加在构造函数下面的,这个时候,通过这个构造函数创建出来的对象,都能共享这个原型下的方法和属性。
看个栗子(原型+构造)
function CreatePerson(name){ this.name = name; } CreatePerson.prototype.showName = function(){ alert(this.name); } var p1 =new CreatePerson(‘haha‘); p1.showName(); var p2 = new CreatePerson(‘hehe‘); p2.showName(); alert(p1.showName==p2.showName);//true
通过最后一句的测试为true,可以看到在构造函数的原型下面加的方法showName()方法是所有通过这个构造函数创建出来的对象所共享的,也就是说他们共用一个内存,更进一步的说它们存在引用关系,也就是说你更改了p1的showName也会影响p2。
所以我们在构造对象的时候,一般是原型模式和构造模式组合使用,变化的用构造模式 不变的用原型模式,就像上面的这个栗子,属性用的构造函数,因为一般不同对象属性都不同,方法用原型模式。
在这里我要介绍一个重要的属性就是constructor
1 它指的是对象的构造函数
2 每个自定义的构造函数都有的属性,当你写完一个构造函数的时候,系统程序会自动在函数的原型下添加对应的构造函数,比如有个自定义构造函数Aaa,系统会自动帮你添加这句话:
Aaa.prototype.construnctor = Aaa;(每个函数都有 都是自动生成的)
所以每个构造函数出生后,原型下面都有这样一个属性了。可以测试一下
function Aaa(){} var a1 = new Aaa(); a1.constructor //Aaa函数
3 所以既然是原型下面的,证明构造函数也是可以被修改的。
function Aaa(){} Aaa.prototype.construnctor=10;//添加 var a1 = new Aaa(); a1.constructor //10
不过要避免修改这个属性。
4 不过有一种情况,我们需要修改,为了创建对象的代码更方便,你一定见过这样的代码,采用Json的方式在原型下加方法,也就是字面量法:
function Aaa(){} Aaa.prototype = { //json 相当于重新赋值了Aaa的原型 ,所以也覆盖掉了 //Aaa.prototype.construnctor = Aaa; num1:function(){alert(10);}, num2:function(){alert(20);}
} var a1 = new Aaa(); a1.constructor //object
这个时候弹出的构造函数竟然变成了object,这是为什么呢,首先我们要知道object是所有对象的最初始的大boss,所有的对象都属于object,其次上面有讲过,每个最开始的构造函数的原型下面都有这样一句话,Aaa.prototype.construnctor = Aaa;这个例子的赋值方式,已经不是在原型上增加方法了,它属于一种赋值的方式,所以就把原来的构造函数给覆盖了,因此我们在写的时候需要修正一下原型的指向。
function Aaa(){} Aaa.prototype = { constructor:Aaa, num1:function(){alert(10);}, num2:function(){alert(20);} } var a1 = new Aaa();
a1.constructor // Aaa
关于JS面向对象之构造对象就先说到这里,其实还有别的不常用的模式,后续会继续补充,如果疏漏,欢迎补充,我是沐晴,不见不散
标签:
原文地址:http://www.cnblogs.com/moqing/p/5593210.html