函数
对于任何语言来说函数都是一个核心概念。通过函数可以封装任意多条语句,而且可以再任何位置、任何时候执行调用。JavaScript通过关键字function来定义函数。函数可以通过声明定义,也可以是一个表达式。
function hello (){ return 'hello' } // 等价于 var hello = function(){ return 'hello' }
根据函数有没有参数和返回值可以把函数分为:有参数函数无返回值函数、无参数函数无返回值函数、有参数无返回值函数、无参数有返回值函数。
function noArgNoRet(){ console.log('无参数函数无返回值函数') } function haveArgNoRet(id){ console.log('有参数函数无返回值函数') } function noArgHaveRet(){ console.log('无参数函数有返回值函数') return 'noArgNoRet' } function haveArgHaveRet(id){ console.log('有参数函数有返回值函数') return 'haveArgHaveRet' }
在刚开始学习时如果要对邮箱、用户名和密码进行验证,一般情况下都会写成一下形式:
function checkName(){ console.log('checkName') } function checkEmail(){ console.log('checkEmail') } function checkPwd(){ console.log('checkPwd') }
这种写法会在全局环境创建出3个全局变量,在功能上时没有问题,但是在多人的团队开发中由于其他的开发人员不知道你所定义的变量名称,很容易就会将其覆盖或者被覆盖的情况。如果将这些变量保存在一个变量中就会大大的减少相互覆盖的风险,一旦产生覆盖现象也会很容易的发现。
var checkObj = { checkName: function (){ // 验证姓名 console.log('checkName') }, checkEmail: function (){ // 验证邮箱 console.log('checkEmail') }, checkPwd: function (){ // 验证密码 console.log('checkPwd') } } // 通过点语法调用 checkObj.checkName() checkObj.checkEmail() checkObj.checkPwd()
虽然如此能满足需求,但是其他人员需要掉用这个对象方法的时候就会比较麻烦。这时我们可以把它放到函数里面进行简单的复制。
var checkObj = function(){ return { checkName: function (){ // 验证姓名 console.log('checkName') }, checkEmail: function (){ // 验证邮箱 console.log('checkEmail') }, checkPwd: function (){ // 验证密码 console.log('checkPwd') } } } // 调用 var check = checkObj(); check.checkName() check.checkEmail() check.checkPwd()
当每次调用这个函数的时候都会将之前的对象返回出来,当别人调用这个函数的时候都会返回一个对象,每个人在使用的时候就不会相互影响了。
构造函数
虽然如此也能满足我们的需求,但是还可以使用构造函数进一步优化。
var CheckObj = function(){ this.checkName = function (){ // 验证姓名 console.log('checkName') } this.checkEmail = function (){ // 验证邮箱 console.log('checkEmail') } this.checkPwd = function (){ // 验证密码 console.log('checkPwd') } } // 调用 var check = new CheckObj(); check.checkName() check.checkEmail() check.checkPwd()
通过构造函数创建对象必须使用关键字new调用,如果不使用new调用,将会污染全局变量。
var CheckObj = function(){ this.checkName = function (){ // 验证姓名 console.log('checkName') } this.checkEmail = function (){ // 验证邮箱 console.log('checkEmail') } this.checkPwd = function (){ // 验证密码 console.log('checkPwd') } } // 调用 var check = CheckObj(); console.log(check) // undefined checkName() // checkName checkEmail() // checkEmail checkPwd() // checkPwd
上面的示例中,我们将方法都放到构造函数的内部,通过this定义,所以每次通过new关键字创建新的对象的时候,新创建的对象都会类的this上的属性进行复制。所以这些新的对象都会有自己的一套方法,这样会造成内存的大量消耗。改造一下,通过使用原型的方法会降低这样的内存消耗。
原型模式
var CheckObj = function(){} /* // es5的写法 CheckObj.prototype.checkName = function (){ // 验证姓名 console.log('checkName') } CheckObj.prototype.checkEmail = function (){ // 验证邮箱 console.log('checkEmail') } CheckObj.prototype.checkPwd = function (){ // 验证密码 console.log('checkPwd') } CheckObj.prototype = { checkName(){ // 验证姓名 console.log('checkName') }, checkEmail(){ // 验证邮箱 console.log('checkEmail') }, checkPwd(){ // 验证密码 console.log('checkPwd') } } */ // es6 Object.assign(CheckObj.prototype, { checkName(){ // 验证姓名 console.log('checkName') }, checkEmail(){ // 验证邮箱 console.log('checkEmail') }, checkPwd(){ // 验证密码 console.log('checkPwd') } }) // 调用 var check = new CheckObj(); check.checkName() // checkName check.checkEmail() // checkEmail check.checkPwd() // checkPwd
这样把三个方法都挂载到CheckObj的原型上,每次创建新的对象的时候就不会对这三个方法重新复制了。通过观察发现在每次调用方法的时候都要写一遍check,我们可以改造一下让它可以使用链式写法。
var CheckObj = function(){} Object.assign(CheckObj.prototype, { checkName(){ // 验证姓名 console.log('checkName') return this }, checkEmail(){ // 验证邮箱 console.log('checkEmail') return this }, checkPwd(){ // 验证密码 console.log('checkPwd') return this } }) // 调用 var check = new CheckObj(); check.checkName().checkEmail().checkPwd() // checkEmail // test.js:11 // checkPwd
如果想要为每个函数都添加这三个方法,可以将这三个方法挂载到Function上,但是一般情况下是不允许这样做的,它会污染原生的Function对象。别人在创建函数的时候也会被这三个函数所污染,造成不必要的开销。但是可以将其抽象成一个添加方法的函数,同时也可以使用链式写法。
Function.prototype.addMethods = function(name, fn){ this[name] = fn return this } var methods = function(){} methods.addMethods('checkName', function(){ // 验证姓名 console.log('checkName') return this }).addMethods('checkEmail', function(){ // 验证邮箱 console.log('checkEmail') return this }).addMethods('checkPwd', function(){ // 验证密码 console.log('checkPwd') return this }) // 调用 methods.checkName().checkEmail().checkPwd() // checkEmail // test.js:11 // checkPwd
另外几种方法:
/* // 第一种 Function.prototype.addMethods = function(name, fn){ this.prototype[name] = fn return this } var Methods = new Function() Methods.addMethods('checkName', function(){ // 验证姓名 console.log('checkName') return this }).addMethods('checkEmail', function(){ // 验证邮箱 console.log('checkEmail') return this }).addMethods('checkPwd', function(){ // 验证密码 console.log('checkPwd') return this }) // 第二种 Function.prototype.addMethods = function(name, fn){} var Methods = new Function().addMethods Object.assign(Methods.prototype, { checkName(){ // 验证姓名 console.log('checkName') return this }, checkEmail(){ // 验证邮箱 console.log('checkEmail') return this }, checkPwd(){ // 验证密码 console.log('checkPwd') return this } }) */ Function.prototype.addMethods = function(name, fn){ return this.addMethods } var Methods = new Function().addMethods() Object.assign(Methods.prototype, { checkName(){ // 验证姓名 console.log('checkName') return this }, checkEmail(){ // 验证邮箱 console.log('checkEmail') return this }, checkPwd(){ // 验证密码 console.log('checkPwd') return this } }) // 调用 var m = new Methods() m.checkName().checkEmail().checkPwd() // checkEmail // test.js:11 // checkPwd
浙公网安备 33010602011771号