跳到主要内容

JavaScript 几种函数编写方式

阅读需 5 分钟

本文总结于《JavaScript 设计模式》(作者是张容铭)这本书第一章,主要讨论JS的几种函数编写方式。

  1. 最基础方法:下面两种方法基本等价,区别是前者的函数名在 function 之后,而后者需要提前声明。
function checkName() {}
function checkEmail() {}
function checkPassword() {}
var checkName = function () {}
var checkEmail = function () {}
var checkPassword = function () {}

优点:简单方便。

缺点:都创建了不少全局变量,方法之间易被相互覆盖。

那么将这些方法放在一个变量里保存,是不是就能减少覆盖几率了?

  1. 用对象收编变量:访问对象的属性和方法时可通过点语法向下遍历得到,所以可以创建一个检测对象,把方法放在里面。
var CheckObject = {
checkName : function () {},
checkEmail : function () {},
checkPassword : function () {}
}
var CheckObject = function () {};
CheckObject.checkName = function () {}
CheckObject.checkEmail = function () {}
CheckObject.checkPassword = function () {}

优点:减少覆盖和被覆盖的风险。

缺点:这个对象类在使用 new 关键字创建新的对象时,新创建的对象不能继承这些方法。

  1. 简单复制对象:将方法放在一个函数对象中,每次调用这个函数的时候,把这个对象返回。
var CheckObject = function () {   
return {
checkName : function () {},
checkEmail : function () {},
checkPassword : function () {}
}
}
// 调用
var a = CheckObject();
a.checkEmail();

优点:每次调用这个函数的时候都返回一个新对象,每个人使用的时候互不影响。

缺点:不是一个真正意义上类的创建方式,且创建的对象 a 与对象 CheckObject 无关系。

  1. 继续改造:将方法放在函数内部,通过 this 定义。
var CheckObject = function () {   
this.checkName = function () {}
this.checkEmail = function () {}
this.checkPassword = function () {}
}
// 调用
var a = new CheckObject(); //注意这个new
a.checkEmail();

优点:每次通过 new 创建新对象时,新对象都会复制类的 this 上的属性,新对象都有自己的一套方法。

缺点:因为是类,所以需要用 new 关键字来创建对象。有时候会很消耗资源。

  1. 节省资源:依赖 prototype 原型依次寻找方法,找到都是绑定在 Object 对象类原型上的同一个方法。
var CheckObject = function () {};
CheckObject.prototype.checkName = function () {}
CheckObject.prototype.checkEmail = function () {}
CheckObject.prototype.checkPassword = function () {}

优点:创建对象实例时,新对象拥有的方法都是一个。

缺点:prototype 需要写很多遍。

那么可以这么改:但这两种方式不可混用,否则后面为对象的原型对象赋值新对象时,会覆盖掉之前对 prototype 对象赋值的方法。

var CheckObject = function () {};
CheckObject.prototype = {
checkName : function () {},
checkEmail : function () {},
checkPassword : function () {}
}
// 调用
var a = new CheckObject();
a.checkName();
a.checkEmail();
a.checkPassword();

在调用的时候 a 对象书写了多遍,还可以加强功能吗?

  1. 加强功能:在声明的每一个方法末尾将当前对象返回。JS 中的 this 指向的就是当前对象。
var CheckObject = {
checkName : function () { return this; },
checkEmail : function () { return this; },
checkPassword : function () { return this; }
}// 调用
CheckObject.checkName().checkEmail().checkPassword();
var CheckObject = function () {}
CheckObject.prototype = {
checkName : function () { return this; },
checkEmail : function () { return this; },
checkPassword : function () { return this; }
}// 调用,使用之前需要创建一下。var a =new CheckObject();
a.checkName().checkEmail().checkPassword();
  1. 介绍 prototype.js 框架 :最大特点是对原生对象(JS 为我们提供的对象类,如 Function、Array、Object…)的拓展,比如想给每一个函数添加一个检测邮箱的方法:
Function.prototype.checkEmail = function () {} 
//函数形式调用
var f = function(){};
f.checkEmail();
//类的形式调用
var f = new Function();
f.checkEmail();

但是这种方法污染了原生对象,别人创建的函数也会被你创建的函数污染。如何解决这个办法?

抽象出一个统一添加方法的功能方法:

Function.prototype.addMethod = function (name, fn) {   
this[name] = fn;
}
//调用
var methods = new Function();
methods.addMethod('checkName', function(){});
methods.addMethod('checkEmail', function(){});
methods.checkName();
methods.checkEmail();

如何链式添加方法呢?

//函数式
Function.prototype.addMethod = function (name, fn) {
this[name] = fn;
return this;
}
var methods = function(){};
methods.addMethod('checkName', function(){
return this;
}).addMethod('checkEmail', function(){
return this;
});
//调用methods.checkName().checkEmail();
//类式
Function.prototype.addMethod = function (name, fn) {
this.prototype[name] = fn;
}
var Methods = function(){};
Methods.addMethod('checkName', function(){
return this;
}).addMethod('checkEmail', function(){
return this;
});
//调用
var m = new Methods();
m.checkEmail();

最后,这本书跟《大话数据结构》的叙述方式都属于风趣类型,一下就吸引了我的注意力…今天读了前两章,收获颇深。觉得必须将知识点总结下来,加强记忆和便于复习。

暂时未加入评论功能,请在对应公众号文章下或 GitHub Issues下留言反馈。