美文网首页
JavaScript 模式(四)

JavaScript 模式(四)

作者: MELODY_DZG | 来源:发表于2016-09-12 21:15 被阅读11次

    函数模式


    1.回调模式

    【基本模式】

      var func = function(callback){
      
          //TODO
          
          //检查回调函数是否可用
          if(typeof callback !== "function"){
             callback = false;
          }
    
          //TODO
          //运行回调函数
          if(callback){
             callback(value);
          }
      }
    

    回调模式下,回调函数作为参数可以是一个已有的函数,也可以是匿名函数

    【作用域】

    在一般方法下,回调函数可以正常运行,但对于对象方法,很可能出现对象方法内调用自身属性,造成this指向不明,其原因是作用域改变:

      //创建对象和对象方法,对象方法调用其属性值
      var objectName = {
          propName: value,
          methodName: function(){
             var other = this.propName;
          }
      }
    
      //使用对象方法作为回调函数
      func(objectName.methodName);//函数调用时出现问题,因为this.propName在相应的作用域内不存在
    

    解决方法一:回调函数参数不仅包含对象方法,也包含该对象,通过绑定限定作用域:

        //更改外层函数的使用方式
        var func = function(callback,obj_callback){
      
          //TODO
          
          //检查回调函数是否可用
          if(typeof callback !== "function"){
             callback = false;
          }
    
          //TODO
          //运行回调函数
          if(callback){
             callback.call(obj_callback,value);
          }
      }
    

    解决方法二:将对象方法的方法名作为参数,按照方法一的模式进行

          var func = function(callback,obj_callback){
      
          //TODO
          
          //检查回调函数赋值参数是否为函数名
          if(typeof callback === "string"){
             callback = obj_callback[callback];//回调函数从对象方法中获得
          }
    
          //TODO
          //运行回调函数
          if(typeof callback === "function"){
             callback.call(obj_callback,value);
          }
    

    【超时用法】

       setTimeout(callback,timeout);
    

    2.返回函数

    将函数作为一个返回值,函数获得返回值后,可以继续调用:

       var outer = function(){
           //在函数声明的作用域中,创建变量,这些变量只能在该域内使用
           var params = value;
          
           //返回一个函数
           return function(){
              //TODO 可以在函数中处理内部参数,对外保持隐蔽
           }
       }
    
       //调用
       var First = outer(); //此时Fisrt即为一个可调用的函数
       var Second = First(); //继续调用
    

    3.自定义函数(惰性函数定义)

    当函数需要初始化工作,且只需要进行一次时,可以使用该模式:

       var selFunc = function(){
          
            //TODO 做一些需要初始化的工作
            
            //注意名称不能改变,因为需要对函数进行重定义
            selFunc = function(){
               //TODO 该函数真正要实现的功能
            };
       }
       
       //使用时
       selFunc(); //第一次进行初始化工作
       selFunc(); //执行真正的功能
    

    【说明】

    • 重定义时,必须要使用相同名称,否则真实功能无法发生
    • 在重定义后,该函数之前添加的属性和方法全部丢失

    4.即时函数

    函数在定义后立即执行的一种模式,包括以下部分:

    • 需要使用函数表达式,不能使用函数声明
    • 在函数主体后添加“()”,表示立即执行
    • 将整个函数包装在括号中
      (function(){
         //TODO
      })();
    

    【使用】
    对于在一些场景中(如页面加载),一些操作只需要进行一次不需要重复使用,没有必要声明函数,如果直接操作,会污染全局域,此时使用即时函数创建沙箱

    【参数和返回值】

    对于含有参数的函数,直接将参数赋值即可,一般可以将全局域本身赋值给函数,就可以调用其中的属性

      (function(region){
         //TODO 使用this中的属性,如DOM元素
      })(this);
    

    返回值可以直接从即时函数获取,返回值或者返回函数均可:

      var result = (function(){
         //TODO
      })();
    

    【预设值】
    可以利用即时函数的特点,直接返回一些预设值,且用户只读不可更改

      var getPreValue = (function(){
         //获取或计算预设值
         var preValue = {
                propName = value
             };
         //通过闭包的方式返回预设值 
         return function(){
            return preValue;
         };
    
      })();
    
      //使用
      var preValue = getPreValue();
      preValue.propName //可以使用预设值
    

    【属性不变量】
    可以利用即时函数给对象的属性赋值,在对象创建时进行赋值后,该属性保持不变

      //定义字面量对象
      var objectName = {
         //定义属性不变量
         constProp: (function(){
             //利用即时函数,直接返回处理结果
             var privateField = value;
             return privateField; 
        })()
      }; 
    
      //使用
      objectName.constProp //直接使用属性不变量
    

    【变种:即时对象初始化】

        //创建匿名对象
       ({
          //这里定义的属性为对象内的属性,不会污染全局域
           propName: value,
           methodName: function(){
           },
           //定义初始化任务
           init: function(){
             //TODO 初始化任务
           }
        }).init(); //直接调用初始化方法
    

    【说明】

    • 该模式可以更有效的组织代码结构
    • 如果要获取该对象,可以在init()中返回this
    • 该模式,在js压缩器工具中,一般不会被压缩

    【变种:初始化分支(加载时分支)】

    初始化时,确定一个条件,该条件在整个程序运行中不会改变,则只需确定一次即可(常见的浏览器嗅探功能,平台确认,函数是否兼容等)

       var mainObj = ({
      
          //需要确认的属性和方法
          propName: null,
          methodName: null,
          
          init: function(){
             //TODO 根据条件给相关属性和方法进行赋值或者定义
             this.propName = value;
             methodName = function(){
             };
          }
    
       }).init();
    
       //使用
       mainObj.propName;
       mainObj.methodName();
    

    6.备忘模式(memoization)

    给函数添加自定义属性,利用该属性缓存函数的返回结果,在下一次相同计算时,无需再做大量计算,直接返回缓存中的结果

       var funcMem = function(param){
           //一般需要将输入参数进行转换,生成一个键值
           var key = param;
           if(! funcMem.cache[key]){
              var result = {};
              //TODO 计算result值
             funcMem.cache[key] = result;
           }
           return funcMem.cache[key]; //返回结果
       };
       funcMem.cache = {};//为函数创建自定义属性
    

    【说明】

    • 创建键值时,一般使用序列化,将输入参数转换为json字符串key = JSON.stringfy(Array.prototype.slice.call(arguments))

    7.配置模式

    函数在需要传递大量参数的情况下,不要直接列在函数参数中,而是传入一个配置对象

      //创建配置对象
      var conf = {
         param_1:value_1,
         param_2:value_2
      };
      
      //传入参数
      func(conf);
    

    【优势】

    • 无需记住所有参数和顺序
    • 可以安全忽略可选参数
    • 易于阅读和维护,易于添加和删除参数
      【劣势】
    • 需要记住参数名称
    • 参数属性无法被压缩器压缩

    8.柯里化(Curry)

    【函数的apply和call】

    函数不仅可以描述为调用,还可以描述为应用

       //原型:Function.prototype.apply()
       //使用: 
       func.apply(region,["param1","param2"]);
    

    【说明】

    • region:表示函数中this所指向的作用域,如果赋值为null则为全局作用域,对于对象方法,必须要赋对象值
    • 参数数组:输入的参数数组,即生成函数的arguments对象
    • call函数为apply的语法糖,即只有一个输入参数时,效率更高:
       func.call(region,"param");
    

    【柯里化过程】

    使函数理解并处理部分应用的过程
    通用实现方法:

       function currify(fn){
          var slice = Array.prototype.slice, //获取数组的原型方法slice()
              stored_args = slice(arguments, 1); //获取参数中第二个至最后的参数
            //返回利用剩余参数构建的新函数
            return function(){
               var new_args = slice.call(arguments), //获取新函数中所有参数
                   args = stored_args.concat(new_args); //并将新参数和原有剩余参数合并在一起,组成新的参数数组
               return fn.apply(null,args); //返回原函数调用
            }
       }
    

    【使用场景】
    如果调用同一个函数,且传递的参数绝大多数都是相同的,则该函数可以用于柯里化

    相关文章

      网友评论

          本文标题:JavaScript 模式(四)

          本文链接:https://www.haomeiwen.com/subject/hbapettx.html