Web 技术研究所

我一直坚信着,Web 将会成为未来应用程序的主流

防呆API设计及flatten概念的引入

  在一些库的编写时,经常会有函数重载(我强调过多少次了,这个词读zhòngzài)的需求。然而,用户可能比较呆。比如一个接收多参数的函数,可能会传入一个数组。根据人性化的设计理念,对这些乱七八糟的操作应该也得支持。所以这里引入flatten的概念。
  比如有一个函数,需要接受任意个数的DOM元素。那么这个函数的参数列表要怎么设计呢?设计成一个不定个数的参数列表,每个参数对应一个DOM元素?我觉得这是最糟糕的设计。或者设计成传入一个数组?也许用户传入的是一个NodeListHTMLCollection这样的拟数组呢?甚至用户会传入一个jQuery对象也有可能吧?而且一次需要传入的数组也许还不止一个。再考虑ES6的话,接口可能被直接传入一个用迭代器来遍历的对象。总之要考虑的情况很多很多!
  怎样设计一个人性化的接口,让这些参数来者不拒呢?参考Promiseresolve时的处理,会将参数中嵌套的所有Promise全部处理掉,这就是flatten的概念。我们也需要类似的工作,将用户传入的参数中,所有数组、拟数组以及可迭代对象,全部干掉,转换成一个扁平的数组(当然,如果你的函数确实需要接受一个数组那就没法使用这个方法了)。这样就不存在接口形式的问题了,当然代价是需要牺牲一点性能。实际上要不是强性能需求的代码,这点性能占用根本算不了什么。(建议:如果是强性能需求的代码建议将接口制作成固定数组,避免函数中对arguments的引用)
  于是就需要有一个用于将用户传入的奇怪参数统一成一个扁平数组的方法。实际上我已经写了这个转换函数,并丢在了Github上。不过我写的是ES6兼容的,去掉兼容的话可以减少很多代码。如果有需要大家可以随意修改着使用,发现BUG也欢迎提出。
  下面放一个目前浏览器兼容的测试代码:
<script src="http://yanagieiichi.github.io/flatten.js/flatten.js"></script>
<script src="http://www.web-tinker.com/share/Promise.js"></script>
<script>
new Promise(function(resolve){
  //创建一个可迭代对象用于测试 @ Firefox32兼容方案
  var iterableObject={};
  //使用Firefox特有的"@@iterator",并使用标准的Generator语法
  iterableObject["@@iterator"]=Function('\
    return function*(){\
      for(var i=1;i<=2;i++)yield "i"+i;\
    };\
  ')();
  resolve(iterableObject);
})["catch"](function(){
  //创建一个可迭代对象用于测试 @ Chrome38兼容方案
  var iterableObject={};
  //使用标准的Symbol.iterator,并且模拟Generator
  iterableObject[Symbol.iterator]=function(){
    var i=1;
    return {next:function(){
      if(i<=2)return {value:"i"+i++,done:false};
      return {value:void 0,done:true};
    }};
  };
  return Promise.resolve(iterableObject);
})["catch"](function(){
  //创建一个可迭代对象用于测试 @ 其它不支持的兼容方案
  var iterableObject={};
  iterableObject[0]="i1";
  iterableObject[1]="i2";
  iterableObject.length=2;
  return Promise.resolve(iterableObject);
}).then(function(iterableObject){
  //准备完毕,开始测试
  var result=flatten(
    [[["ok1"],"ok2"]], //嵌套的数组
    document.getElementsByTagName("script"), //HTMLCollection
    {0:"a1",1:"a2",length:2}, //拟数组
    iterableObject, //可迭代对象
    {0:1,1:2,length:null}, //非拟数组且不可迭代(会被保留)
    function(a,b){} //函数(会被保留)
  );
  //输出结果
  console.log(result);
  /*[
    "ok1", "ok2", //来自嵌套的数组
    script, script, script, //来自HTMLCollection
    "a1", "a2", //来自拟数组
    "i1", "i2", //来自可迭代对象
    Object, //来自非拟数组且不可迭代(被保留)
    function //来自函数(被保留)
  ]*/
})["catch"](function(e){
  //输出其它未预料的错误
  console.log(e);
});
</script>
网名:
52.91.185.*
电子邮箱:
仅用于接收通知
提交 悄悄的告诉你,Ctrl+Enter 可以提交哦
神奇海螺
[查看全部主题]
各类Web技术问题讨论区
发起新主题
本模块采用即时聊天邮件通知的模式
让钛合金F5成为历史吧!
次碳酸钴的技术博客,文章原创,转载请保留原文链接 ^_^