JavaScript是目前最流行、应用最普遍的语言之一,它是一种极富表现力的语言,它具备C家族语言所罕见的特性。这种语言容许咱们使用各类方式来完成同一个任务或者功能,还容许咱们在面向对象编程的过程使用函数式编程中的概念来丰富其实现方式。这种语言容许咱们采用多种不一样的编程风格进行编程,如简单一些的函数式编程,复杂一些的面向对象编程。因此咱们能够在长期的编码过程当中,培养专门属于本身的编程风格,下面的例子会体现出JavaScript的灵活性。html
下面咱们将要实现一个模拟开始播放音乐和中止播放音乐的小功能,代码以下:编程
1 /************************************************/ 2 //方法一:传统的函数式编码方式 3 function start() { 4 console.log("music start"); 5 } 6 7 function stop() { 8 console.log("music stop"); 9 } 10 11 //页面调用方法一 12 start(); 13 stop(); 14 /************************************************/ 15 //方法二:利用prototype 16 var Player=function() {} //声明function对象 17 18 Player.prototype.start=function(){ //为对象的prototype添加方法 19 console.log("music start by prototype"); 20 } 21 Player.prototype.stop=function(){ 22 console.log("music stop by prototype"); 23 } 24 25 //页面调用方法二 26 Player =new Player(); 27 Player.start(); 28 Player.stop(); 29 /************************************************/ 30 //方法三:prototype进一步封装 31 var ControlPlayer=function(){} 32 33 ControlPlayer.prototype={ 34 start:function () { 35 console.log("music start prototype-start"); 36 }, 37 stop:function(){ 38 console.log("music stop prototype-stop"); 39 } 40 } 41 42 //页面调用方法三 43 var c=new ControlPlayer(); 44 c.start(); 45 c.stop(); 46 /************************************************/ 47 //方法四:经过prototype添加方法,链式调用 48 Function.prototype.method=function(name,fn){ //注意function的大小写,小写会不识别句点 49 this.prototype[name]=fn; 50 return this;//链式调用 51 } 52 53 ControlPlayer.method('start',function(){ 54 console.log('music starting by chain... ...'); 55 }).method('stop',function(){ 56 console.log('music stopping by chain... ...'); 57 }); 58 59 60 //页面调用方法四 61 ControlPlayer.prototype.start(); 62 ControlPlayer.prototype.stop(); 63 64 /************************************************/ 65 //方法五:经过prototype添加方法,非链式调用 66 Function.prototype.method=function(name,fn){ //注意function的大小写,小写会不识别句点 67 this.prototype[name]=fn; 68 //return this;//链式调用 69 } 70 71 ControlPlayer.method('start',function(){ 72 console.log('music starting... ...'); 73 }); 74 75 ControlPlayer.method('stop',function(){ 76 console.log('music stopping... ...'); 77 }); 78 79 //页面调用方法五,同四 80 ControlPlayer.prototype.start(); 81 ControlPlayer.prototype.stop();
方法一很简单,可是没法建立能够保存状态而且具备一些仅仅对其内部状态进行操做的方法的对象;方法二中将两个方法(start、stop)赋给该类的prototype属性;若是但愿把类的定义封装在一块儿,能够采用方法三的作法;方法四中使用Function.prototype.method为该类添加新的方法,它有两个参数,第一个是字符串型的方法名称,第二个是具体的好函数;若是对方法四进行扩展,可让它返回this,这样就能够进行链式调用,也就是方法五的内容。经过以上的几个例子能够发现,不使用prototype属性定义的对象方法,是静态的,只能用类名进行调用,另外此静态方法中没法使用this关键字来调用对象的其余属性;而使用prototype属性定义的对象方法,是非静态的,只有在实例化以后才能调用,其方法内部可使用this关键字来调用对象的其余属性;只有function才能被实例化,而Object则不能被实例化,前者能够经过new操做符,然后者能够经过赋值把对象保存在变量中并经过该变量对其内部成员进行访问;若是是对象中的function,须要new一下这个function再使用。设计模式
在Javascript中,声明变量时能够不指定类型,可是这不意味着变量没有类型,变量的类型取决于变量的值。在Javascript中有5中原始类型,分别是Number、String、Boolean、Undefined和Null,此外还有对象类型Object和包含可执行代码的函数类型,前者是一种复合数据类型(数组也是Object类型,它包含着一批有序的值集合)。原始类型按值传递,而其余类型包括复合对象是按引用传递。Javascript中,能够经过赋值来改变数据类型,原始数据类型之间也能够进行转换,toString方法能够把Number和Boolean类型转成字符串,parseFloat和parseInt能够把字符变为数值型,双重非操做能够把Number和String转成Boolean类型。弱类型的变量带来了极大的灵活性,Javascript会根据值进行自动转换。数组
在Javascript中,函数能够存储在变量中,能够做为参数传给其余函数,能够做为返回值从其余函数传出,还能够在运行时进行构造,这些特性带来了极大的灵活性和极强的表达能力,而这些正是构建传统面向对象的框架基础。下面的代码建立了一个匿名函数并赋值给一个变量,代码以下:网络
1 (function(){ 2 console.log('anonymous function!'); 3 })(); //此处括号表示当即调用,另外若是没有分号,多个匿名函数时会报错 4 5 (function(){ 6 var a=20; 7 var b=10; 8 console.log(a*b); 9 })(); 10 11 (function(a,b){ 12 console.log(a*b); 13 })(12,13);//括号中传入的参数和function中的形参一致,参数由外部传入 14 15 var result =(function(a,b){ 16 return a*b; 17 })(3,3); 18 console.log(result);//result的值是匿名函数的返回值
匿名函数最有趣的用途是用于建立闭包(closure),闭包是一个受到保护的变量空间,由内嵌函数生成。Javascript具备函数级的做用域,这意味着在函数内部定义的变量在函数的外部是不能够访问的。Javascript的做用域是词法性质,这意味着函数是运行在定义它的做用域中,而不是调用它的做用域中。把这两个因素结合起来,就能够经过把变量包裹在匿名函数中而对其加以保护,代码以下:闭包
1 var item; 2 (function(){ 3 var a=12; 4 var b=23; 5 item=function(){ 6 return a*b; 7 }; 8 })(); 9 10 item();
变量a和b定义在匿名函数中,由于函数item定义在这个闭包中,因此它能访问这两个变量,即便是在该闭包结束后。架构
在JavaScript中,一切都是对象,除了那几种基本类型,即使是基本类型,在必要的时候也会被自动包装为对象,全部对象都是易变的(mutable),这意味着能够在JavaScript中使用其余语言不容许的技术。例如,为函数添加属性:框架
1 function displayError(msg) { 2 displayError.numTimesExcuted++;//新增属性 3 alert(msg); 4 } 5 6 displayError.numTimesExcuted=0;
这意味着能够对先前的类或实例化的对象进行修改,代码以下:函数式编程
1 //定义Person类 2 function Person(name,age){ 3 this.name=name; 4 this.age=age; 5 } 6 //为Person类添加GetName和GetAge方法 7 Person.prototype={ 8 GetName:function(){ 9 return this.name; 10 }, 11 GetAge:function(){ 12 return this.age; 13 } 14 } 15 //新建一个Person类的实例tom 16 var tom=new Person('tom',21); 17 var name=tom.GetName(); 18 console.log(name); 19 20 //为Person类添加Greeting方法 21 Person.prototype.Greeting=function(){ 22 return 'hi,'+this.GetName(); 23 } 24 //新建一个Person类的实例lucy 25 var lucy=new Person('lucy',23); 26 console.log(lucy.Greeting()); 27 //为tom实例添加displayGreeting方法 28 tom.displayGreeting=function(){ 29 alert(this.Greeting()); 30 } 31 tom.displayGreeting();
在这个例子中,Greeting方法是在建立Person类的两个实例(tom、lucy)以后添加的,可是这两个实例依然可以访问到,这是由于prototype的工做机制。对象tom还获得了displayGreeting方法,这是其余实例所没有的。与对象的易变性相关的还有一个内省(introspection)的概念,在运行时检查对象所具备的属性和方法,还可使用这种方法动态地建立类和执行其方法,这种技术称之为反射(reflection),大多数模仿传统面向对象的特性的技术都是基于对象的易变性和反射。在JavaScript中,任何东西均可以在运行时动态地改变,固然也有不利的一面,由于咱们定义一个具备一套方法的类,到最后却不能把保证它依旧无缺如初。函数
JavaScript中的继承并不是传统的面向对象的真正的继承,而是基于prototype原型链的继承方式,它能够用来模拟传统的基于类的继承方式,可是性能略有差别,具体的使用还要看需求。
JavaScript的强大的表现力赋予了咱们在运用设计模式编写代码时极大的创造性,在JavaScript中使用设计模式主要有如下几个缘由:
<1>可维护性:有助于下降模块间的耦合性,使代码重构和换用不一样的模块变得容易,使得代码维护更加容易;
<2>沟通方便:设计模式为处理不一样类型的对象提供了一套通用的术语,这样编码人员在沟通时只要讲明采用的设计模式便可清晰地表达,而没必要涉足更细节层次的东西;
<3>提高性能:某些设计模式会大幅提高应用的性能,减小网络传输,好比享元模式和代理模式,固然也有好多设计模式会下降性能,这个就须要使用者自行把握。
JavaScript的丰富表现力是其力量之源,即便这种弱类型语言没有本身的内置对象,可是咱们能够随时根据本身的需求进行扩展,因为其实弱类型语言,因此定义变量时并不须要指定类型。函数是一等对象,而且能够动态建立,所以能够建立闭包;全部的对象都是易变的,能够在运行时修改;可使用的继承方式有两种,一种是原型链继承、另外一种是类式继承,它们各有优缺点。JavaScript的设计模式并不是彻底有益,须要使用者根据具体的需求进行决策,使用不当甚至会产生负面的效果,过分复杂的架构会把应用程序拖入泥沼,因此要根据咱们本身的编码风格选择适合的模式来完成具体的工做。
做者:悠扬的牧笛
博客地址:http://www.cnblogs.com/xhb-bky-blog/p/5866675.html
声明:本博客原创文字只表明本人工做中在某一时间内总结的观点或结论,与本人所在单位没有直接利益关系。非商业,未受权贴子请以现状保留,转载时必须保留此段声明,且在文章页面明显位置给出原文链接。