前言:

本篇主要是介绍 JavaScript使用函数的高级方法,函数是JavaSCript中最有趣的部分,利用Function特性可以编写出很多非常有意思的代码,本篇主要包括:函数回调,高阶函数以及函数柯里化。

 
1.   函数回调
     对于异步编程JavaScript API如SetTimeout或者JQuery的$.ajax又或者越来越火的Node.js编程,在事件循环上都是非阻塞的,意思就是,当你使用异步非阻塞API的使用,调用在回调函数执行之前立即返回,而这些回调在不久之后执行。
 setTimeout(function(){
console.log("hello");
},2000)
// ... 大概2s之后(实际上大于2s)
// => hello

Node中一个非阻塞代码实例

创建一个文件 input.txt ,内容如下:

 “Hello World” 

创建 main.js 文件, 代码如下:

 var fs = require("fs");
// 封装一个readFile函数
var readFile=function(filename,callback){
fs.readFile('input.txt', function (err, data) {
if (err) return callback(err);
return callback(null,data);
});
}
//调用
readFile('input.txt',function(err,data){
if(err)
handle(err);
else
handle(data);
}
我们不需要等待文件读取完,这样就可以在读取文件时同时执行接下来的代码,由回调函数执行处理读取的文件内容,大大提高了程序的性能。

JQuery的XMLHttpRequest也是利用回调执行异步编程

 $.get( "example.php", function() {
alert( "success" );
})
.done(function() {
alert( "second success" );
})
.fail(function() {
alert( "error" );
})
.always(function() {
alert( "finished" );
});
 
2.   高阶函数
     高阶函数可以分为:
  1. 以其他函数为参数的函数
  2. 返回其他函数的函数
    这一部分更偏向于JavaScript函数式编程的部分,但是利用高阶函数可以构建功能更强大的函数,所以在这里讲了一下。
 
  1. 以其他函数为参数的函数
    
       其实,回调函数也是属于这种模式,利用这种模式,我们可以实现Model和Action层的逻辑分离,举个例子吧
       我们利用数据库做了一个小型的登录用户检查,添加和删除。   
    •    建立一个 model/User.js 主要负责和数据库进行数据的增删查改
 var mysql = require('mysql');
var pool = mysql.createPool({
// 登录数据库的配置
});
function addUser(param,callback) {
pool.getConnection(function(err, connection) {
if(err) return callback(err);
var $sql="INSERT INTO user(id, password) VALUES(?,?)";
connection.query( $sql, [param.id, param.password],function(err, result) {
if(err)
return callback(err);
else
connection.release();
return callback(null,result);
});
});
}
    • 通过传入添加数据和一个回调函数作为参数,我们在视图层可以自定义对添加失败和成功的操作,而无需理会和数据库的具体操作,当数据库发生变化的时候,只需要修改model的User.js,实现外模式和模式的逻辑独立性
 

2. 返回其他函数的函数

          这里我们将了解返回函数和闭包的高阶函数
          举个例子,我们创建一个makeAdder的高阶函数,他的参数配置了其返回函数每次添加数值的大小

 function makeAdder(addVal){
return function(arg){
return addVal+arg;
}
}
var add2=makeAdder(2);
var a=add2(10)
console.log(a);
// => 12
 
按照这样子我们可以自由配置 add10,add5等等。。。
[注]: 其实这里运用了闭包的知识,我们都知道闭包会保存外部函数的作用域链,可以捕获外部函数的参数;当我们返回一个add2()函数的时候,这个函数会一直记住外部函数的addVal的值
[缺点]:过度使用闭包,会造成内存泄漏,就像上面的add2()函数,会一直保存着外部函数的作用域链,直到自己被销毁
 
 
3.   函数柯里化
 
         柯里化函数为每一个逻辑参数返回一个新函数。函数柯里化的基本方法和函数绑定是一样的:使用一个闭包返回一个函数。
        其实上面的makeAdder()其实也可以算是一种柯里化函数,返回的是一个函数,但从技术上讲,并不算是真正意义上的柯里化函数,我们来看一个真正意义的柯里化函数例子:

 function curry(fn){
  var args=[].slice.call(arguments,1);
  return function(){
  var innerArgs=[].slice.call(arguments);
  var finalArgs=args.concat(innerArgs);
  return fn.apply(null,finalArgs);
  }
}
 function add(){
var args=Array.prototype.slice.call(arguments);
return args.reduce(function(prev,next){
return prev+next;
});
}
 var curryAdd=curry(add);
var result=curryAdd(1,2,3);
console.log(result);
// => 6
var curryAdd2=curry(add,2);
var result=curryAdd2(2,3);
console.log(result);
// => 7
两种方式都可以,第二个函数可以代表一个 加2函数
curry()函数的主要工作就是将返回函数的参数进行排序。curry()的第一个参数是要进行柯里化的函数,其他参数是要传入的值。利用[].slice.call(arguments,1) 获取外部函数的参数;在内部函数中,使用innerArgs存放所有传入的参数,最后使用concat将所有参数组合成finalArgs,利用apply()将参数传递给fn函数。
[注意]:这个函数没有考虑执行环境,所以调用apply()的第一个参数为null。
[缺点]:利用柯里化函数可以实现复杂的算法和功能,但是都不可以滥用,因为他们是基于闭包实现的,会带来一定的开销。
 
 
 
 
 
 
 
 
 
 
 
 

JavaScript系列:高级函数篇的更多相关文章

  1. 深入理解JavaScript系列(结局篇)

    介绍 最近几个月忙得实在是不可开交,终于把<深入理解JavaScript系列>的最后两篇“补全”了,所谓的全是不准确的,因为很多内容都没有写呢,比如高性能.Ajax安全.DOM详解.Jav ...

  2. 30s源码刨析系列之函数篇

    前言 由浅入深.逐个击破 30SecondsOfCode 中函数系列所有源码片段,带你领略源码之美. 本系列是对名库 30SecondsOfCode 的深入刨析. 本篇是其中的函数篇,可以在极短的时间 ...

  3. javascript系列-class4.函数

    欢迎加入前端交流群来py: 转载请标明出处!                   在火影的世界中存在忍术,忍术是把强大的能量集中在一起以各种各样不同的形式发射出来.怎样使用各种各样的忍术那?通过结印. ...

  4. JavaScript系列:函数 自执行 表达式 声明 定义

    可用方式 (function($) {})(jQuery); !function( $ ){}(jQuery); +function( $ ){}(jQuery); -function( $ ){}( ...

  5. javascript之高级函数应用思想

    1.级联函数:应用对象方法调用的连写 function A(){ this.a = ''; this.b = ''; this.c = ''; } //改造一下 A.prototype = { A.p ...

  6. javaScript的高级函数

    1.map() map()方法返回一个新数组,新数组是原始数组调用函数之后处理后的值. map()方法按照原始数组元素顺序依次处理元素. map不会对空数组进行检测. map不会改变原始数组 . 参数 ...

  7. Oracle高级函数篇之递归查询start with connect by prior简单用法

    路飞:" 把原来CSDN的博客转移到博客园咯!" 前段时间,自己负责的任务中刚好涉及到了组织关系的业务需求,自己用了oracle递归查询.下面简单来举个例子.在工作中我们经常会遇到 ...

  8. 深入理解JavaScript系列

    转自http://www.cnblogs.com/TomXu/archive/2011/12/15/2288411.html 深入理解JavaScript系列(1):编写高质量JavaScript代码 ...

  9. 深入理解JavaScript系列(转自汤姆大叔)

    深入理解JavaScript系列文章,包括了原创,翻译,转载,整理等各类型文章,如果对你有用,请推荐支持一把,给大叔写作的动力. 深入理解JavaScript系列(1):编写高质量JavaScript ...

随机推荐

  1. 第6章 事务管理 6.1 spring事务

    事务管理——原子性.一致性.隔离性.持久性 理解spring对事务管理的支持 Spring提供对编码式和声明式事务管理的支持.编码式事务允许用户在代码中精确定义事务的边界,而声明式事务(基于AOP,面 ...

  2. gym/102059/problem/I. Game on Plane SG函数做博弈

    传送门: 题意: 给定一个正n边形的点.双方轮流连点成线,要求所画的线不能与之前的线相交.当某个人连成一个回路,这个人就输了.问先手必胜还是后手必胜. 思路: SG函数,因为一条线相当于把图劈成了两半 ...

  3. codeforces 1041 E. Tree Reconstruction 和度数有关的构造树

    CF 1041E:http://codeforces.com/contest/1041/problem/E 题意: 告诉你一个树的节点个数,显然有n-1条边.已知去掉一条边后,两个集合中最大的节点值. ...

  4. 从一道看似简单的面试题重新理解JS执行机制与定时器

     壹 ❀ 引 最近在看前端进阶的系列专栏,碰巧看到了几篇关于JS事件执行机制的面试文章,因为我在之前一篇 JS执行机制详解,定时器时间间隔的真正含义 博文中也有记录JS执行机制,所以正好用于作为测试自 ...

  5. Redis缓存穿透、缓存雪崩、并发问题分析与解决方案

    (一)缓存和数据库间数据一致性问题 分布式环境下(单机就不用说了)非常容易出现缓存和数据库间的数据一致性问题,针对这一点的话,只能说,如果你的项目对缓存的要求是强一致性的,那么请不要使用缓存.我们只能 ...

  6. Zookeeper内部实现分布式数据一致性(底层系统模型)(一)

    Zookeeper的几个概念:(接下来将从这几个概念书写Zookeeper的内部工作流程) 数据模型 节点特性 版本 Watcher ACL <1> 数据模型: Zookeeper的视图很 ...

  7. JavaScript如何给td赋值

    td里加个标签,如: <td><div id="aa"></div></td> document.getElementById('a ...

  8. 使用Python SMTP发送邮件

    import smtplibfrom email.mime.text import MIMEText # 服务器SMPTserver = "smtp.163.com"# 发送邮件的 ...

  9. HTML连载37-边框属性(下)、边框练习

    一.边框属性 1.连写(分别设置四条边的边框) border-width:上 右 下 左: border-style:上 右 下 左: border-color:上 右 下 左: 注意点: (1)这三 ...

  10. @Qualifier高级应用---按类别批量依赖注入【享学Spring】

    每篇一句 罗斯:选秀状元可能有水货,但MVP绝对没有 前言 在上篇文章(讲解@LoadBalanced负载均衡)的末尾,我抛出了一个很重要的问题,建议小伙伴自己深入思考一番:本文主要针对此问题,作出一 ...