javascript --- Function模式
回调函数
在javascript中,当一个函数A作为另外一个函数B的其中一个参数时,则称A函数为回调函数,即A可以在函数B的运行周期内执行(开始,中间,结束)。
举例来说,有一个函数用于生成node.
var complexComutation = function(){
// 内部处理,并返回一个node
}
又有一个findNodes函数声明用于查找所有节点,然后通过callback回调进行执行代码。
var findNodes = function(callback){
var nodes = [];
var node = complexComputation();
// 如果回调函数可用,则执行她
if(typeof callback === 'function'){
callback(node);
}
nodes.push(node);
return nodes;
}
关于callback的定义,我们可以事先定义好来用:
// 定义callback
var hide = function(node){
node.style.display = 'node';
}
var hiddenNodes = findNodes(hide);
也可以在调用的时候使用匿名定义,如下:
// 使用匿名定义callback
var blockNodes = findNodes(function(node){
node.style.display = 'block';
})
我们平时用的最多的,估计就数jQuery的ajax方法的调用了,通过在done/faild上定义callback,以便在ajax调用成功或者失败的时候做进一步处理,代码如下(本代码基于jquery1.8版):
var menId = $('ul.nav').first().attr('id');
var request = $.ajax({
url: 'script.php',
type: 'post',
data: {id: menuId},
dataType: 'html'
})
// 调用成功时的回调处理
request.done(function(msg){
$('#log').html(msg);
})
// 调用失败时的回调处理
request.fail(function(jqXHR, textStatus){
alert('Request failed:' + textStatus);
});
配置对象
如果一个函数(或方法)的参数只有一个,并且参数为对象字面量,我们则称这种模式为配置对象模式。如下所述:
var her = {
username: 'gaohan',
first: 'gao',
last: 'han'
};
addPerson(her);
则在addPerson函数内部,就可以随意使用her对象内的值了,一般用于初始化工作,例如jquery里的ajaxSetup也就是这种方式来实现的:
// 事先设置好初始值
$.ajaxSetup({
url: '/xmlhttp/',
global: false,
type: 'POST'
})
// 然后再调用
$.ajax({ data:myData });
另外,很多jquery的插件也有这种形式的传参,只不过也可以不传,不传的时候则就使用默认值了。
返回函数
返回函数,则是指一个函数的返回值为另一个函数,或者根据特定的条件灵活创建的新函数,示例如下:
var setup = function(){
console.log(1);
return function(){
console.log(2);
};
};
// 调用setup函数
her();
// 或者直接调用也可以;
setup()(); // 2
或者我们可以利用闭包的特性,在函数中加入一个计数器,用来计算函数被调用的次数:
var setup = function(){
var count = 0;
return function(){
retunr ++count;
};
};
var next = serup();
next();
next();
next();
Currying
Currying是函数式编程的一个特性,将多个参数的处理转化成单个参数的处理,类似链式调用。
下面来举一个简单的例子:
function add(x, y){
var oldx = x, oldy = y;
if(typeof oldy === 'undefined'){
return function (newy){
return oldx + newy;
}
}
return x + y ;
}
这样的话,调用方式就有很多种了,比如:
// 测试 typeof add(5); // 'function' add(3)(4); // 也可以这样调用 var add2000 = add(2000); add2000(10);
接下来我们定义一个,比较常用的currying函数:
// 第一个参数为要应用的function, 第二个参数是需要传入的最少参数个数
function curry(func, minArgs) {
if(minArgs == undefined) {
minArgs = 1;
}
function funcWithArgsFrozen(frozenargs){
return function () {
// 优化处理,如果调用时没有参数,返回该函数本身
var ages = Array.prototype.slice.call(arguments);
var newArgs = frozenargs.concat(args);
if(newArgs.length >= minArgs) {
return func.apply(this, newArgs);
}else{
return funcWithArgsFrozen(newArgs);
}
}
}
return funcWithArgsFrozen([]);
}
这样,我们就可以随意定义我们的业务行为了,比如定义加法:
var plus = curry(function(){
var result = 0;
for(var i=0; i<arguments.length; ++i){
result += arguments[i];
}
return result;
}, 2)
使用方法多种多样。
plus(3, 2) // 正常调用 plus(3) // 偏应用 plus(3) (2) // 完整应用(返回5) plus() (3) () () (2) // 返回5 plus(3, 2, 4, 5) // 可以接受多个参数 plus(3) (2, 3, 5) // 同理
JavaScript里的Function有很多特殊的功效,可以利用闭包以及arguments参数特性实现很多不同的技巧,下一篇我们将继续介绍利用Function进行初始化的技巧。
立即执行的函数
// 声明完函数以后,立即执行该函数
(function (){
console.log('watch out');
}());
// 这种方式声明的函数,也可以立即执行
!function(){
console.log('watch out!');
}();
// 如下的方式也都可以哦
~function(){ /* do someing*/ }();
-function(){ /* do someing*/ }();
+function(){ /* do someing*/ }();
立即执行的对象初始化
该模式的意思是指在声明一个对象(并非函数)的时候、立即执行对象里的某一个方法进行初始化工作,通常该模式可以用在执行一次性的代码上:
({
// 这里你可以定义常量,并设置其它值
maxwidth: 600,
maxheight: 400,
// 当然也可以定义方法
gimmMax: function(){
return this.maxwidth + 'x' + this.maxheight;
},
init: function(){
console.log(this.gimmeMax());
// 更多代码......
}
}).init(); // 这样就能初始化喽
分支初始化
分支初始化是指在初始化的时候,根据不同的条件(场景)初始化不同的代码,也就是所谓的条件语句赋值。之前我们在处理的时候,常常使用类似下面的代码:
var utils = {
addListener: function(el, type, fn){
if(typeof window.addEventListener === 'function'){
el.addEventListener(type, fn, false);
}else if(typeof document.attachEvent !== 'undefined'){
el.attachEvent('on' + type, fn);
}else{
el['on' + type] = fn;
}
},
removeListener: function(el, type, fn){
// 神马之类的......
}
}
我们来改进一下,首先我们要定义两个接口,一个用来add事件句柄,一个用来remove事件句柄,代码如下:
var utils = {
addListener: null,
removeListener: null
};
实现代码如下:
if (typeof window.addEventListener === 'function') {
utils.addListener = function (el, type, fn) {
el.addEventListener(type, fn, false);
};
} else if (typeof document.attachEvent !== 'undefined') { // IE
utils.addListener = function (el, type, fn) {
el.attachEvent('on' + type, fn);
};
utils.removeListener = function (el, type, fn) {
el.detachEvent('on' + type, fn);
};
} else { // 其它旧浏览器
utils.addListener = function (el, type, fn) {
el['on' + type] = fn;
};
utils.removeListener = function (el, type, fn) {
el['on' + type] = null;
};
}
用起来,是不是就很方便了?代码也优雅多了。
自声明函数
一般是在函数内部,重写重名函数代码,比如:
var her = function(){
alert('Boo!');
her = function(){
alert('Double Boo!!');
}
}
这种代码,非常容易使人迷惑,我们先来看看例子的执行结果:
// 1.添加新属性
scareMe.prototype = 'Anna';
// 2. scareMe赋予一个新值
var prank = scareMe;
// 3. 作为一个方法调用
var spooky = {
boo: scareMe
}
// 使用新变量名称进行调用
prank(); // 'Boo!'
prank(); // 'Boo!'
console.log(spooky.boo.property); // 'properly'
通过执行结果,可以发现,将定于的函数赋值与新变量(或内部方法),代码并不执行重载的scareMe代码,而如下例子则正好相反:
// 使用自声明函数 scareMe(); // Double boo! scareMe(); // Double boo! console.log(scareMe.property); // undefined
大家使用这种模式时,一定要非常小心才行,否则实际结果很可能和你期望的结果不一样,当然你也可以利用这个特殊做一些特殊的操作。
内存优化
该模式主要是利用函数的属性特性来避免大量的重复计算。通常代码形式如下:
var myFunc = function (param) {
if (!myFunc.cache[param]) {
var result = {};
// ... 复杂操作 ...
myFunc.cache[param] = result;
}
return myFunc.cache[param];
};
// cache 存储
myFunc.cache = {};
但是上述代码有个问题,如果传入的参数是toString或者其它类似Object拥有的一些公用方法的话,就会出现问题,这时候就需要使用传说中的hasOwnProperty方法了,代码如下:
var myFunc = function (param) {
if (!myFunc.cache.hasOwnProperty(param)) {
var result = {};
// ... 复杂操作 ...
myFunc.cache[param] = result;
}
return myFunc.cache[param];
};
// cache 存储
myFunc.cache = {};
或者如果你传入的参数是多个的话,可以将这些参数通过JSON的stringify方法生产一个cachekey值进行存储,代码如下:
var myFunc = function () {
var cachekey = JSON.stringify(Array.prototype.slice.call(arguments)),
result;
if (!myFunc.cache[cachekey]) {
result = {};
// ... 复杂操作 ...
myFunc.cache[cachekey] = result;
}
return myFunc.cache[cachekey];
};
// cache 存储
myFunc.cache = {};
或者多个参数的话,也可以利用arguments.callee特性:
var myFunc = function (param) {
var f = arguments.callee,
result;
if (!f.cache[param]) {
result = {};
// ... 复杂操作 ...
f.cache[param] = result;
}
return f.cache[param];
};
// cache 存储
myFunc.cache = {};
总结
javascript --- Function模式的更多相关文章
- javascript运行模式:并发模型 与Event Loop
看了阮一峰老师的JavaScript 运行机制详解:再谈Event Loop和[朴灵评注]的文章,查阅网上相关资料,把自己对javascript运行模式和EVENT loop的理解整理下,不一定对,日 ...
- Javascript原型模式总结梳理
在大多数面向对象语言中,对象总是由类中实例化而来,类和对象的关系就像模具跟模件一样.Javascript中没有类的概念,就算ES6中引入的class也不过是一种语法糖,本质上还是利用原型实现.在原型编 ...
- JavaScript严格模式详解
转载自阮一峰的博客 Javascript 严格模式详解 作者: 阮一峰 一.概述 除了正常运行模式,ECMAscript 5添加了第二种运行模式:"严格模式"(strict m ...
- (转)深入理解JavaScript 模块模式
深入理解JavaScript 模块模式 (原文)http://www.cnblogs.com/starweb/archive/2013/02/17/2914023.html 英文:http://www ...
- JavaScript严谨模式(Strict Mode)
下面的内容翻译自It’s time to start using JavaScript strict mode,作者Nicholas C.Zakas参与了YUI框架的开发,并撰写了多本前端技术书籍,在 ...
- Javascript编程模式(JavaScript Programming Patterns)Part 1.(初级篇)
JavaScript 为网站添加状态,这些状态可能是校验或者更复杂的行为像拖拽终止功能或者是异步的请求webserver (aka Ajax). 在过去的那些年里, JavaScript librar ...
- JQuery日记6.5 Javascript异步模式(一)
理解力JQuery前实现异步队列,有必要理解javascript异步模式. Javascript异步其实并不严重格异步感,js使某些片段异步方式在将来运行,流不必等待继续向下进行. 在多线程的语言中最 ...
- 浅析JavaScript工厂模式
这里主要介绍两种工厂模式,第一种“简单工厂模式”,第二种“工厂方法模式” 简单工厂模式 1.定义 由一个工厂对象决定对象创建某一种产品对象的的实例.主要用来创建同一类对象. 2.具体需求 现在有一个登 ...
- Javascript 严格模式(strict mode)详解
Javascript 严格模式详解 一.概述 除了正常运行模式,ECMAscript 5添加了第二种运行模式:"严格模式"(strict mode).顾名思义,这种模式使得Ja ...
随机推荐
- 哈夫曼树(三)之 Java详解
前面分别通过C和C++实现了哈夫曼树,本章给出哈夫曼树的java版本. 目录 1. 哈夫曼树的介绍 2. 哈夫曼树的图文解析 3. 哈夫曼树的基本操作 4. 哈夫曼树的完整源码 转载请注明出处:htt ...
- testing - 测试基本使用接口
testing - 测试基本使用接口 当你写完一个函数,结构体,main之后,你下一步需要的就是测试了.testing包提供了很简单易用的测试包. 写一个基本的测试用例 测试文件的文件名需要以_tes ...
- iOS平台快速发布HT for Web拓扑图应用
iOS平台一直是封闭的生态圈,iOS开发者要缴纳年费加入开发者计划才可进行iOS平台的APP开发测试,所开发的APP需要上传到App Store经过苹果审核以后才可对外发布.如果要开发企业内部应用,则 ...
- EF基本操作增、删、查、改、分页,join……等
一.批量添加数据 static void Main(string[] args) { add(); add2(); Console.ReadKey(); } static void add() { D ...
- Java - 容器详解
一.ArrayList 长度可变数组,类似于c++ STL中的vector. 元素以线性方式连续存储,内部允许存放重复元素. 允许对元素进行随机的快速访问,但是向ArrayList中插入和删除元素的速 ...
- jQuery+CSS3实现404背景动画特效
效果:http://hovertree.com/texiao/jquery/74/ 源码下载:http://hovertree.com/h/bjaf/ko0gcgw5.htm 效果图如下: 代码如下: ...
- 提升VMware虚拟机性能招数
在VMware虚拟机(VMware Workstation或VMware Server)中我们可以同时运行多个Guest OS,当同时在同一Host OS中运行多台虚拟机时势必会严重影响到Host O ...
- sql查询重复记录和from子查询
select name from (SELECT name,count(name) as countFROM Table WHERE (OrgUUId = (select top 1 uuid fro ...
- jquery子元素选择器
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- line-height 属性
p.small {line-height:90%} p.big {line-height:200%} 该属性会影响行框的布局.在应用到一个块级元素时,它定义了该元素中基线之间的最小距离而不是最 ...