JavaScript 面向对象及设计模式系列--灵活的JavaScript,Timo.Lee
当前,Javascript已经成为世界上最受欢迎和被广泛应用的的编程语言--因为他被捆绑到各种浏览器中。作为一种编程语言,它已经渗透到人们的日常生活中,它为我们访问的网站带来了更加好的用户体验。
很多人很轻视JavaScrpt--它只是玩具,成为一个专业的JavaScript Programmer很不值得. 我想是因为那些人还没有意识到JavaScirpt强大的能力和在编程世界的不可代替性。JavaScript 是一门很松散,灵活的编程语言,有很多特征与C 家族不一样。
接下来,我们一起去探究一下JavaScirpt的灵活性---用数种不同的方法去实现相同的功能。当然,我还会和大家分享如果从面向过程编程转变到面向对象编程。我们还会探讨为什么我们优先选择用设计模式和怎么把设计模式融入到JavaScirpt当中。
JavaScript的可扩展性:
可 扩展性是一门强大的编程语言的标志。作为一名Javascipt 开发人员,我们可以用简单方法或者复杂的方法来构建应用—It’s up to you.JavaScirpt 也存在很多种编程风格,你可以用简单的函数方式或者更复杂的面向对象方法,这是为什么很多人认为javascript是玩具的原因。
我们可以用JavaScript去模仿其他编程语言的模式与风格。当然,我们完成可以模仿Server-Side 的面向对象编程语言的风格。
下以开始和停止动画作为例子,看看怎么用不同的方法去实现同样的功能:
面向过程编程方式:
1 |
/*Start and stop animation using functions*/ |
2 |
3 |
function startAnimation(){ |
4 |
...................... |
5 |
} |
6 |
7 |
function stopAnimation(){ |
8 |
......................... |
9 |
} |
这种实现方式很简单,但是它不允许你创建Animation对象来保持动画的状态(属性)和行为(方法)。接下来我们用面向对象的方式来解决这一问题:
01 |
/**Animation Class**/ |
02 |
var Animation= function (){ |
03 |
........ |
04 |
}; |
05 |
06 |
Animation.prototye.start= function (){ |
07 |
........ |
08 |
}; |
09 |
10 |
Animation.prototype.stop= function (){ |
11 |
.......... |
12 |
}; |
13 |
14 |
/*Demo*/ |
15 |
16 |
var Anim= new Animation(); |
17 |
Anim.start(); |
18 |
......... |
19 |
Anim.stop(); |
上面,我们定义了一个类叫Animation,它持有两种不同的行为,strat,stop。如果我们更希望把方法都集中地声明,我们可以用下面的方式:
01 |
/**Animation class**/ |
02 |
03 |
var Animation= function (){ |
04 |
............... |
05 |
}; |
06 |
07 |
Animation.prototype={ |
08 |
start:{ |
09 |
......... |
10 |
}, |
11 |
stop:{ |
12 |
........ |
13 |
} |
14 |
}; |
1 |
|
1 |
对于使用Java,C #等面向对象编程的开发人员,这种编程丰富应该有种似曾相识的感觉吧---类声明-->方法在类中声明。下面我们再把代码改进一下,让风格更贴近面向对象的风格: |
1 |
|
01 |
/*Add a method to the Function object that can be use to declare method...*/ |
02 |
03 |
Function.prototype.method= function (name,fn){ |
04 |
this .prototype[name]=fn; |
05 |
}; |
06 |
07 |
/*Animation Class*/ |
08 |
09 |
var Animation= function (){ |
10 |
11 |
............ |
12 |
}; |
13 |
14 |
Animation.method( "start" , function (){ |
15 |
............ |
16 |
}); |
17 |
18 |
Animation.method( "stop" , function (){ |
19 |
............... |
20 |
}); |
1 |
Function.protoype.method(fnName,fn) 让我们可以在所有的JavaScript类中添加方法。第一个参数是要添加方法的名字,第二个方法是要添加方法的函数体。 |
1 |
最后,我们可以把Funtion.prototype.method方法改进一下,让它实现类型与jQuery的链式调用: |
01 |
/*Add a method to the Function object that can be use to declare method...*/ |
02 |
03 |
Function.prototype.method= function (name,fn){ |
04 |
this .prototype[name]=fn; |
05 |
return this ; |
06 |
}; |
07 |
08 |
/*Animation Class*/ |
09 |
10 |
var Animation= function (){ |
11 |
12 |
............ |
13 |
}; |
14 |
15 |
/*Clain call*/ |
16 |
Animation.method( "start" , function (){ |
17 |
............ |
18 |
}).method( "stop" , function (){ |
19 |
............... |
20 |
}); |
1 |
|
1 |
相信,通过上面的例子,大家应该慢慢体会到JavaScript可扩展性和灵活性的强大魅力了吧。 |
1 |
|
1 |
|
1 |
<strong>松散的(loosely-typed)编程语言</strong> |
1 |
<strong> </strong>在JavaScript 使用过程中,我们不需声明变量的类型,但是不代表该变量没有类型。根据变量中装载的数据不同,变量可以是几中类型。 |
1 |
基本的3种类型:Booleans,Numbers,String.(JavaScript 把整型与浮点型当中同一种类型). |
1 |
function ,它包含一段可执行的代码。这里还有对象(object),它可以包含多种数据类型在其中,如Array。 |
1 |
null 与undefined这两种数据类型。 |
1 |
基本类型是值传递的,而其他类型是通过引用(指针,地址)传递的,这一点很重要,如果不清楚这点,在编程过程中可能引起不可预知的问题。 |
1 |
|
1 |
<strong>函数--特殊的对象</strong> |
1 |
<strong> </strong>在JavaScript的编程语言中,函数是特殊的对象。它们能够储存在变量中,也可以以参数的形式传递到另一个函数中, 也可以作为函数的返回值。这些特征为JavaScript带来极大扩展性和丰富的表达方法。 |
1 |
例如,你可以用 function (){…}创建匿名函数,它没有指定函数名,但是它可以任意赋值给其他变量,看下面简单的例子: |
1 |
/*Anonymous function,execude immediately*/ |
2 |
( function (){ |
3 |
var price=1.2; |
4 |
var number=10; |
5 |
alert(price*number) |
6 |
})(); |
1 |
|
1 |
上面的这个函数在没有赋值到变量就已经定义和执行了,代码最后的括号声明了这个函数立刻执行。我们看到括号中没有任何参数,但是,我们也可以定义参数,这样,匿名函数就可以获得这些参数,看下面代码例子: |
1 |
/**An anonymous function with argument**/ |
2 |
( function (){ |
3 |
alert(price*number) |
4 |
})(price,number); |
1 |
|
1 |
当然,匿名函数还可以作为返回值,看下面例子: |
1 |
var totalPrice=( function (){ |
2 |
return price*number; |
3 |
})(10,10); |
// totalPrice=100
用匿名函数构造闭包(closure)
什么是闭包?闭包简单来说就是一块受保护的区域,通过函数嵌套产生。JavaScript 有函数范围的作用域,换句话说,定义在函数内部的变量外部不能访问。有趣的JavaSript是函数是常量作用范围,也就是说函数运行在它定义好的域中, 而不是在运行在执行它的域。综合这两个特征,我们就可以把我们要保护的变量放进匿名函数中。实际面向对象编程中,我们可以用这种方式为类创建私有变量,例 子如下:
01 |
/*an anonymous function as closure*/ |
02 |
03 |
var totalPrice; |
04 |
05 |
(funciton{ |
06 |
var price=10; |
07 |
var number=10; |
08 |
totalPrice= function () |
09 |
{ |
10 |
price*number; |
11 |
}; |
12 |
})(); |
13 |
14 |
//totalPrice(); |
1 |
从上例看出,即使totalPrice 在匿名函数外部,它也可以访问 price 和 number.更复杂的问题,我们会在后面的文章中继续探讨闭包的应用. |
1 |
|
1 |
|
1 |
<strong>对象可变动性</strong> |
1 |
在JavaScirpt的世界中,任何东西都是对象(除了三种基本的数据类型外)。而且,更有趣的是,所有对象都是可以随机改变的。这些特征可以赋予Javascript 其他语言没有的能力,如动态添加属性: |
1 |
function logTarce() |
2 |
{ |
3 |
LogTrce.timer++; |
4 |
alert( "Log trace..." ); |
5 |
} |
6 |
7 |
LogTrace.timer=0; |
这意味着我们可以在类定义后修改类,或者是对象初始化之前修改对象:
01 |
/*Class Person*/ |
02 |
var Person= function (name,age) |
03 |
{ |
04 |
this .name=name; |
05 |
this .age=age; |
06 |
} |
07 |
08 |
Person.protoytpe.getAge= function (){ |
09 |
return this .age; |
10 |
}; |
11 |
Person.prototype.getName= function (){ |
12 |
return this .name; |
13 |
} |
14 |
15 |
16 |
/*instantiate the class*/ |
17 |
18 |
var timo= new Person( "timo" ,25); |
19 |
20 |
/*modify the class*/ |
21 |
22 |
Person.prototype.sayWelcome= function (){ |
23 |
alert( "Hi" + this .name+ ",welcome to timo.lee's tech blog" ); |
24 |
} |
25 |
26 |
/*modify the specific instance*/ |
27 |
28 |
timo.helloTimo= function (){ |
29 |
alert( "Hello Timo" ); |
30 |
}; |
在上面这些例子中,我们看到我们既可以在类定义后修改类,可以是对象实例化后修改对象。
关于继承
相比与传统的面向对象语言,JavaScript 不能直接地(声明的方式)实现继承。但是JavaScript 可以用基于对象(prototypal)的方式实现/模拟继承。
JavaScript 中使用设计模式
相信提起设计模式,大家都会想起gof(四人帮).设计模式只是一种经验\模式,它可以在任何语言中实现,所有JavaScript也不例外,在往后的文章在,会和大家一起探讨这个主题.
相信,大家都慢慢体验到JavaScript的强大力量了吧.