zoukankan      html  css  js  c++  java
  • JavaScript系列:高级函数篇

    前言:

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

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

    Node中一个非阻塞代码实例

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

     “Hello World” 

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

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

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

     1 $.get( "example.php", function() {
     2 alert( "success" );
     3 })
     4 .done(function() {
     5 alert( "second success" );
     6 })
     7 .fail(function() {
     8 alert( "error" );
     9 })
    10 .always(function() {
    11 alert( "finished" );
    12 });
     
    2.   高阶函数
         高阶函数可以分为:
    1.  以其他函数为参数的函数
    2. 返回其他函数的函数
        这一部分更偏向于JavaScript函数式编程的部分,但是利用高阶函数可以构建功能更强大的函数,所以在这里讲了一下。
     
    1.  以其他函数为参数的函数
        
           其实,回调函数也是属于这种模式,利用这种模式,我们可以实现Model和Action层的逻辑分离,举个例子吧
           我们利用数据库做了一个小型的登录用户检查,添加和删除。   
      •    建立一个 model/User.js 主要负责和数据库进行数据的增删查改
     1 var mysql = require('mysql');
     2 var pool = mysql.createPool({
     3 // 登录数据库的配置
     4 });
     5 function addUser(param,callback) {
     6 pool.getConnection(function(err, connection) {
     7 if(err) return callback(err);
     8 var $sql="INSERT INTO user(id, password) VALUES(?,?)";
     9 connection.query( $sql, [param.id, param.password],function(err, result) {
    10 if(err)
    11 return callback(err);
    12 else
    13 connection.release();
    14 return callback(null,result);
    15 });
    16 });
    17 }
      •   通过传入添加数据和一个回调函数作为参数,我们在视图层可以自定义对添加失败和成功的操作,而无需理会和数据库的具体操作,当数据库发生变化的时候,只需要修改model的User.js,实现外模式和模式的逻辑独立性
     
       2. 返回其他函数的函数
              这里我们将了解返回函数和闭包的高阶函数
              举个例子,我们创建一个makeAdder的高阶函数,他的参数配置了其返回函数每次添加数值的大小
      
    1 function makeAdder(addVal){
    2 return function(arg){
    3 return addVal+arg;
    4 }
    5 }
    6 var add2=makeAdder(2);
    7 var a=add2(10)
    8 console.log(a);
    9 // => 12
     
    按照这样子我们可以自由配置 add10,add5等等。。。
    [注]: 其实这里运用了闭包的知识,我们都知道闭包会保存外部函数的作用域链,可以捕获外部函数的参数;当我们返回一个add2()函数的时候,这个函数会一直记住外部函数的addVal的值
    [缺点]:过度使用闭包,会造成内存泄漏,就像上面的add2()函数,会一直保存着外部函数的作用域链,直到自己被销毁
     
     
    3.   函数柯里化
     
             柯里化函数为每一个逻辑参数返回一个新函数。函数柯里化的基本方法和函数绑定是一样的:使用一个闭包返回一个函数。
            其实上面的makeAdder()其实也可以算是一种柯里化函数,返回的是一个函数,但从技术上讲,并不算是真正意义上的柯里化函数,我们来看一个真正意义的柯里化函数例子:
     1 function curry(fn){
     2   var args=[].slice.call(arguments,1);
     3   return function(){
     4   var innerArgs=[].slice.call(arguments);
     5   var finalArgs=args.concat(innerArgs);
     6   return fn.apply(null,finalArgs);
     7   }
     8 }
    1 function add(){   
    2      var args=Array.prototype.slice.call(arguments);
    3      return  args.reduce(function(prev,next){
    4                   return prev+next;
    5              });
    6 }
    1 var curryAdd=curry(add);
    2 var result=curryAdd(1,2,3);
    3 console.log(result);
    4 // => 6
    5 var curryAdd2=curry(add,2);
    6 var result=curryAdd2(2,3);
    7 console.log(result);
    8 // => 7
    9  两种方式都可以,第二个函数可以代表一个 加2函数
    curry()函数的主要工作就是将返回函数的参数进行排序。curry()的第一个参数是要进行柯里化的函数,其他参数是要传入的值。利用[].slice.call(arguments,1) 获取外部函数的参数;在内部函数中,使用innerArgs存放所有传入的参数,最后使用concat将所有参数组合成finalArgs,利用apply()将参数传递给fn函数。
    [注意]:这个函数没有考虑执行环境,所以调用apply()的第一个参数为null。
    [缺点]:利用柯里化函数可以实现复杂的算法和功能,但是都不可以滥用,因为他们是基于闭包实现的,会带来一定的开销。
     
     
     
     
     
     
     
     
     
     
     
     
  • 相关阅读:
    react 入坑笔记(五)
    练习
    高级指令
    进阶指令
    基础指令
    VMware 备份操作系统
    Ubuntu 用户的切换
    形态学转换
    图像模糊
    域名拆分 tld
  • 原文地址:https://www.cnblogs.com/kasmine/p/6349400.html
Copyright © 2011-2022 走看看