javascript进阶之路1
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了javascript进阶之路1相关的知识,希望对你有一定的参考价值。
路漫漫其修远兮,吾将秃了头依然不见大明湖畔的夏雨荷。
当年我还是个javascript小白,项目经理分下来一个验证表单功能的任务,内容不多,仅需要验证用户名、邮箱、密码等。
我一看so easy,于是便写下几个函数。
1 function checkName () { 2 //验证姓名 3 } 4 5 function checkEmail () { 6 //验证邮箱 7 } 8 9 function checkPassword () { 10 //验证密码 11 }
正要将吾之杰作提交到团队项目里。
正在此时,一位头发稀疏,脑壳发亮,满脸胡渣的长者看着将要提交的代码摇了摇头说:“小白,等一下,先不要提交。”
“怎么了?”
“你创建了很多全局变量呀。”
“全局变量?我只是写了几个函数而已。”
“函数不是变量么?”长者反问道。
此时小白不知所措,心想:“难道函数是变量?”脸瞬间黑了下来。
长者见状忙笑着说:“别着急,你看,如果我这么声明几个变量来实现你的功能你看可以么?”
1 var checkName = function () { 2 //验证姓名 3 } 4 5 var checkEmail = function () { 6 //验证邮箱 7 } 8 9 var checkPassword = function () { 10 //验证密码 11 }
“一样的,只不过。。。。。。”
“对,只不过这个在用的时候要提前声明,但是这么看你就会发现你创建了3个函数保存在变量里来实现你的功能,而你写的是将你的变量名放在function后面而已,它也代表了你的变量。所以说你也声明了3个全局变量。”
“这有什么问题呢?”
“从功能上讲当然没问题,但是今天你加入了我们的团队,在团队开发中你所写的代码就不能只考虑自己了,也要考虑不影响到他人,如果别人也定义了同样的方法就会覆盖掉原有的功能了。如果你定义了很多方法,这种相互覆盖的问题是很不容易察觉到的。”
“那我应该如何避免呢?”
“你可以将它们放在一个变量里保存,这样就可以减少覆盖或被覆盖的风险,当然一单被覆盖,所有的功能都会失效,这种现象也是很明显的,你自然也会很轻易地察觉到。”
“可是我该如何做呢?”小白迫不及待滴问道。
“一猜你就会问。”
“好吧,请你先简单滴说一下。”
“对象你知道吧,它有属性和方法,而如果我们要访问它的属性或方法时,可通过点语法向下遍历查询得到。我们可以创建一个检测对象,然后把我们的方法放在里面。”
1 var CheckObject = { 2 checkName : function () { 3 //验证姓名 4 }, 5 checkEmail : function () { 6 //验证邮箱 7 }, 8 checkPassword : function () { 9 //验证密码 10 }, 11 }
“此时我们将所有的函数作为CheckObject对象的方法,这样我们只有一个对象,而我们要想使用它们也很简单,比如检测姓名CheckObject.checkName(),只是在我们原来使用的函数式前面多了一个对象名称。”
“哦,这样啊,但是我们既然可以通过点语法来使用方法,我们是不是也可以这么创建呢?”
“当然,不过首先你要声明一个对象,然后给它添加方法,当然在javascript中函数也是对象,所以你可以这么做:”
1 var CheckObject = function () {}; 2 CheckObject.checkName = function () { 3 //验证姓名 4 } 5 CheckObject.checkEmail = function () { 6 //验证邮箱 7 } 8 CheckObject.checkPassword = function () { 9 //验证密码 10 }
“使用和前面一样,比如CheckObject.checkName(),”长者接着说,“现在虽然能满足你的需求,但当别人想用你的写的对象方法时就有些麻烦了,因为这个对象不能复制一份,或者说这个对象类在用new关键字创建新的对象时,新创建的对象是不能继承这些方法的。”
“但是复制又有什么用呢?”小白不解地问道。
“给你举个例子吧,假如你有一百块,你的小伙伴看见了也想要一百块,可只有一百块怎么办?但如果你有一台印钞机,那么好吧,谁想要就给他印一百。”
“哦,有些明白了,但是我该如何做呢?”
长者解释道:“如果你想简单地复制一下,你可以将这些方法放在一个函数对象中。”于是长者将代码写下。
1 var CheckObject = function () { 2 return { 3 checkName : function () { 4 //验证姓名 5 }, 6 checkEmail : function () { 7 //验证邮箱 8 }, 9 checkPassword : function () { 10 //验证密码 11 } 12 } 13 }
小白看了看代码,思考一下说:“哦,你写的看上去是,当每次调用这个函数的时候,把我们之前写的那个对象返回出来,当别人每次调用这个函数时都返回了一个新对象,这样执行过程中明面上是CheckObject对象,可实际上是返回的新对象。这样每个人在使用时就互不影响了。比如想检测邮箱可以像这样吧。”
1 var a = CheckObject (); 2 a.checkEmail ();
“嗯,对”长者接着说,“虽然通过创建了新对象完成了我们的需求,但是他不是一个真正意义上类的创建方式,并且创建的对象a和对象CheckObject没有任何关系(返回出来的对象本身就与CheckObject对象无关),所以我们还要对其稍加改造一下。”
1 var CheckObject = function () { 2 this.checkName = function () { 3 //验证姓名 4 } 5 this.checkEmail = function () { 6 //验证邮箱 7 } 8 this.checkPassword = function () { 9 //验证密码 10 } 11 }
“像上面这样的对象就可以看成类了。”长者继续说。
“那么我们使用它还想之前那样创建对象的方法创建么?”小白追问道。
“不,既然是一个类,你就要用关键字new来创建了。”
1 var a = new CheckObject(); 2 a.checkEmail();
“这样你就可以用CheckObject类创建出来的对象了。”
“如果我和我的小伙伴们都对类实例化了(用类创建对象),那么我们每个人都会有一套属于自己的方法吧。”小白不解地问道。
“当然,你看,我们是把所有的方法放在函数内部了,通过this定义的,所以每一次通过new关键字创建新对象的时候,新创建的对象都会对类的this上的属性进行复制。所以这些新创建的对象都会有一套自己的方法,然而有时候这么做造成的消耗是很奢侈的,我们需要处理一下。”
1 var CheckObject = function () { 2 3 }; 4 CheckObject.prototype.checkName = function () { 5 //验证姓名 6 } 7 CheckObject.prototype.checkEmail = function () { 8 //验证邮箱 9 } 10 CheckObject.prototype.checkPassword = function () { 11 //验证密码 12 }
“但有一点你要记住,这两种方法不能混着用,否则一旦混用,如在后面为对象的原型对象赋值新对象时,那么它将会覆盖掉之前对prototype对象赋值的方法。”长者补充说。
“知道了,不过我们要使用这种方式定义的类是不是要像下面这样呢?”小白问道。
1 var a = new CheckObject(); 2 a.checkName(); 3 a.checkEmail(); 4 a.checkPassword();
“没错,但是你发现没,你调用了3个方法,但是你对对象a书写了3遍。这是可以避免的,那就要在你声明的每一个方法末尾处将当前对象返回,在javascript中this指向的就是当前对象,所以你可以将它返回。例如我们开始写的第一个对象还记得么?改动它很简单,像下面这样就可以。”
1 var CheckObject = { 2 checkName : function () { 3 //验证姓名 4 return this; 5 }, 6 checkEmail : function () { 7 //验证邮箱 8 return this; 9 }, 10 checkPassword : function () { 11 //验证密码 12 return this; 13 }, 14 }
“此时我们要想使用它就可以这样:”
1 CheckObject.checkName().checkEmail().checkPassword();
“当然同样的方式还可以放到类的原型对象中。”
1 var CheckObject = function () {}; 2 CheckObject.prototype = { 3 checkName : function () { 4 //验证姓名 5 return this; 6 }, 7 checkEmail : function () { 8 //验证邮箱 9 return this; 10 }, 11 checkPassword : function () { 12 //验证密码 13 return this; 14 } 15 }
“但使用时候也要先创建一下:”
1 var a = new CheckObject(); 2 a.checkName().checkEmail().checkPassword();
小白回顾着这些从未见过的代码方式内心很激动,长者见小白对JavaScript如此着迷,于是补充了两句。
“如果你看过prototype.js的代码,我想你会想到下面的书写方式。”
“prototype.js是什么?”小白问道。
“一款javascript框架,里面为我们方便地封装了很多方法,它最大的特点就是对原生对象(JavaScript语言为我们提供的对象类,如Function、Array、Object等)的拓展,比如你想给每一个函数都添加一个检测邮箱的方法就可以这么做。”
1 Fucntion.prototype.checkEmail = function () { 2 //验证邮箱 3 }
“这样你在使用这个方法的时候就比较方便了,如果你习惯函数形式,那么你可以这么做。”
1 var f = new Function(); 2 f.checkEmail();
“但是你这么做在我们这里是不允许的,因为你污染了原生对象Function,所以别人创建的函数也会被你创建的函数所污染,造成不必要的开销,但你可以抽象出一个统一添加方法的功能方法。”
1 Function.prototype.addMethod = function (name, fn) { 2 this[name] = fn; 3 }
“这样如果你想添加邮箱验证和姓名验证方法你可以这样做。”
1 var methods = function () {};
或者
1 var methods = new Function(); 2 methods.addMethod(‘checkName‘, function () { 3 //验证姓名 4 }); 5 methods.addMethod(‘checkEmail‘, function () { 6 //验证邮箱 7 }); 8 methods.checkName(); 9 methods.checkEmail();
“呀,这种方式很奇特呀。不过我想链式添加方法,是不是在addMethod中将this返回就可以呀,这么做可以么?”
1 Function.prototype.addMethod = function (name, fn) { 2 this[name] = fun; 3 return this; 4 }
“当然,所以你再想添加方法就可以这样了:”
1 var methods = function () {}; 2 methods.addMethod(‘checkName‘, function () { 3 //验证姓名 4 }).addMethod(‘checkEmail‘, function () { 5 //验证邮箱 6 });
“那么小白,我问你,我如果想链式使用你知道该如何做么?”
小白想了想说,既然添加方法的时候可以将this返回实现,那么添加的每个方法将this返回是不是就可以实现呢?”
于是小白这么写下:
1 var methods = function () { 2 }; 3 methods.addMethod(‘checkName‘, function () { 4 //验证姓名 5 return this; 6 }).addMethod(‘checkEmail‘, function () { 7 //验证邮箱 8 return this; 9 }); 10 11 methods.checkName().checkEmail();
“真的可以呀!”小白兴奋滴说。
“可是在你测试的时候,你用的是函数式调用方式?对于习惯于类式调用方式的同学来说,他们可以这样简单更改一下。”
1 Function.prototype.addMethod = function (name, fn) { 2 this.prototype[name] = fn; 3 return this; 4 }
“此时我们还按照上一种方式添加方法。”
1 var Methods = function() {}; 2 Methods.addMethod(‘checkName‘, function () { 3 //验证姓名 4 }).addMethod(‘checkEmail‘, function () { 5 //验证邮箱 6 });
“但是我们在使用时就要注意了,不能直接使用,要通过new关键字来创建新对象了。”
1 var m = new Methods(); 2 m.checkEmail();
小白兴奋滴看着这一行行代码情不自禁地叫了一声“这真是一种艺术”。
以上是关于javascript进阶之路1的主要内容,如果未能解决你的问题,请参考以下文章
JavaScript的进阶之路函数简介,变量作用域和内存问题