您的位置:首页 > Web前端 > JavaScript

js面向对象程序设计

2011-08-18 21:47 369 查看
这个算是js高级的内容,可能有一些人看起来会有点压力。建议大

家去看下我之前发的几篇关于js的博客。
由于大部分代码都是直接用记事本直接写的,所以就没太注意大小

写的问题。
js里面没有类的概念 ,所谓的面向对象都是模拟出来的。

首先说一个js方法的重要的属性,prototype,这个属性就是方法

的原型,保存它们所有实例方法的真实存在。就是说,比如

toString()和valueOf()等方法实际上都保存在prototype名下,只

不过通过各自对象的实例访问罢了。
每个函数都包含两个非继承而来的方法:apply()和call()
用在特定的作用域调用函数,实际上等于设置函数体内this对象的

值。
apply接收两个参数:在其中运行的作用域,参数数组function

sum(x,y)
{return x+y;
}
function applySum1(x,y)
{
return sum.apply(this,arguments);
}
function applySum2(x,y){
return sum.apply(this,[x,y]);
}
alertapplySum1(1,2));
alertapplySum2(1,2));
在使用call()方法时,必须明确地传入每一个参数。结果和apply

一样。
其实apply和call真正的强大用途在于,能够扩充函数赖以运作的

作用域:
window.color="red";
var o ={color:"blue"};
function sayColor(a,b){alert(this.color);}
sayColor();
sayColor.call(this,1,2);
sayColor.call(window,1,2);
sayColor.call(o,1,2);
这样扩充的最大好处,就是对象不需要与方法有任何耦合关系。

上面的call和apply不做重点介绍,大家想仔细了解的话可以在网

上找些资料仔细了解下,要是仔细的说的话一下子也说不完。

一、首先创建js对象的四种方式:
1,普通模式,
var person=new Object();
person.name="盼盼";
person.age=22;
person.sayHi=function(){
alert(this.name);
}
但是这样每次去创建一个类的对象相当的麻烦。所以有了下面的集

中创建对象的模式。
2,工厂模式.
function person(name,age){
var p=new Object();
p.name=name;
p.age=age;
p.sayHi=function(){
alert(this.name);
};
return p;
}
这样就创建一一个person类(并不是真正意义上的方法,其实我们

能看到,它只不过是一个方法,一个Object的对象的实例而已,里

面所谓的属性,只不过是以Object特有的键值对的形式存在)。
var p1 = person("盼盼",22);
var p2 = person("明明",26);
p1.sayHi();
p2.sayHi();
这个结果,应该猜都能猜出来。

3,构造函数模式
function person(name,age){
this.name=name;
this.age=age;
this.sayHi=function(){
alert(this.name);};
}
var p1 = new person("盼盼",22);
var p2 = new person("明明",26);
p1.sayHi();
p2.sayHi();
new关键字:
1开辟堆空间;
2创建对象;
3将构造函数作用域赋值给新对象(this就指向了该新对象);
4执行构造函数中的代码(为新对象添加属性);
5返回新对象

4,原型模式,其实上面的集中方法都有大家看不到的缺陷。
每个实例上都有自定义的各个方法对象,这样多个对象调用这个方

法的时候就消耗内存资源。我们在想能不能让同一个类的对象都区

调用同一个方法对象。这样就不会占用那么多的内存空间。
好,这个时候prototype的好处就体现了。
function person(name,age){
this.name=name;
this.age=age;
}
person.prototype.sayHi=function(){
alert(this,name);
}
var p1 = new person("盼盼",22);
var p2 = new person("明明",26);
p1.sayHi();
p2.sayHi();

二、继承
1,方法的继承,首先用原型模式创建一个父类。
function Person(name,age){
this.name=name;
this.age=age;
}
Person.prototype.sayHi=function(){
alert(this,name);
}

2,创建子类,
function Student()
{
}
Student.prototype=Person.prototype;
var stu=new Person();
如何判断stu继承了person??
***只要stu能点出sayHi这个方法出来就证明stu能够调用这个方法

,也就是说继承了这个方法。
stu.sayHi();
很显然的能点出来
运行的话,会弹出undefinde,既然弹出了,就证明方法执行了,

方法执行了就证明方法继承过来的,至于弹出的我们下面来解决。
//这样子类student就能够继承父类的方法。
但是这样父类的属性还没有继承过来,这个时候就需要考虑用到

apply或者call方法,来改变函数的作用域了。

我们更改下这个子类的构造函数
function Student()
{
Person.apply(this,["panpan",22])
}
这个时候我们在执行sayhi这个方法的时候就会弹出panpan。
那这个时候我们的继承就好解决了,我们可以在student这个类中

传2个参数,name,age。然后在apply中的第二个参数设置为name

和age的数组。
function Student(name, age) {
Person.apply(this, [name, age])
}

好吧,我们看下完整的代码。
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.sayHi = function () {
alert(this.name);
}
function Student(name, age) {
Person.apply(this, [name, age])
}
Student.prototype = Person.prototype;
var stu = new Student("盼盼", "22");
stu.sayHi();
这样我们的继承问题就解决了。
Student.prototype = Person.prototype;
这个代码是把person的原型指针赋给了student的原型
也就是说我们给Student.prototype添加一个属性的时候,父类

person也会具有这个属性。
Student.prototype.eat = function () {
alert(this.name+"我在吃饭");
}
var per = new Person("明明", 26);
per.eat();

这个时候就会弹出“明明我在吃饭”
但是var per = new Person("明明", 26);
per.eat();

这个代码必须放在Student.prototype.eat = function () {
alert(this.name+"我在吃饭");
}
之后,因为代码是从上到下执行的。
在没有给原型指针添加属性方法的时候是没办法访问到的。
上述的代码也就是说我们在给子类添加方法的时候,我们父类也有

了这些方法,但是理论上来说对于继承是不允许这样的。
那么我们怎么对子类添加方法而不会使父类也拥有这些方法呢。
我们看一下,stu调用sayHi方法是怎么执行的。
首先创建一个stu的对象,在栈上保存这个变量stu,在堆上保存

new出来的对象,stu这个变量指向堆上对象的地址。当我们调用

stu的sayHi方法时,首先会到student这个对象去找方法,找不到

这个方法,然后去原型里面去找, 由于这个方法的原型实质上是

person类的原型的地址。所有就到person类中区找,找到了就调用

这个方法。
如果我们将子类的原型指向父类的对象呢?
Student.prototype = new Person();
我想大家仔细看了的都应该豁然开朗了。
这样就实现了js的继承
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: