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的进阶之路函数简介,变量作用域和内存问题

JavaScript的进阶之路引用类型之Object类型和Array类型

java进阶之路

webpack4之路-优化进阶

Java程序设计进阶之路四:抛出异常