深入探讨javascript函数式编程(2)

// 把信息打印到屏幕中央的函数 var printCenter = function(str) { var elem = document.createElement("div"); elem.textContent = str; elem.style.position = 'absolute'; elem.style.top = window.innerHeight / 2 + "px"; elem.style.left = window.innerWidth / 2 + "px"; document.body.appendChild(elem); }; printCenter('hello world'); // 纯函数完成相同的事情 var printSomewhere = function(str, height, width) { var elem = document.createElement("div"); elem.textContent = str; elem.style.position = 'absolute'; elem.style.top = height; elem.style.left = width; return elem; }; document.body.appendChild( printSomewhere('hello world', window.innerHeight / 2) + 10 + "px", window.innerWidth / 2) + 10 + "px"));

非纯函数依赖window对象的状态来计算宽度和高度,自给自足的纯函数则要求这些值作为参数传入。 实际上它就允许了信息打印到任何地方,这也让这个函数有了更多用途。

非纯函数看起来是一个更容易的选择,因为它在自己内部实现了追加元素,而不是返回元素。 返回了值的纯函数printSomewhere()则会在跟其他函数式编程技术的配合下有更好的表现。

var messages = ['Hi', 'Hello', 'Sup', 'Hey', 'Hola']; messages.map(function(s, i) { return printSomewhere(s, 100 * i * 10, 100 * i * 10); }).forEach(function(element) { document.body.appendChild(element); });

当一个函数是纯的,也就是不依赖于状态和环境,我们就不用管它实际是什么时候被计算出来。 后面的惰性求值将讲到这个。

匿名函数

把函数作为头等对象的另一个好处是匿名函数。

就像名字暗示的那样,匿名函数就是没有名字的函数。实际不止这些。它允许了在现场定义临时逻辑的能力。 通常这带来的好处就是方便:如果一个函数只用一次,没有必要给它浪费一个变量名。

下面是一些匿名函数的例子:

// 写匿名函数的标准方式 function() { return "hello world" }; // 匿名函数可以赋值给变量 var anon = function(x, y) { return x + y }; // 匿名函数用于代替具名回调函数,这是匿名函数的一个更常见的用处 setInterval(function() { console.log(new Date().getTime()) }, 1000); // Output: 1413249010672, 1413249010673, 1413249010674, ... // 如果没有把它包含在一个匿名函数中,他将立刻被执行, // 并且返回一个undefined作为回调函数: setInterval(console.log(new Date().getTime()), 1000) // Output: 1413249010671

下面是匿名函数和高阶函数配合使用的例子

function powersOf(x) { return function(y) { // this is an anonymous function! return Math.pow(x, y); }; } powerOfTwo = powersOf(2); console.log(powerOfTwo(1)); // 2 console.log(powerOfTwo(2)); // 4 console.log(powerOfTwo(3)); // 8 powerOfThree = powersOf(3); console.log(powerOfThree(3)); // 9 console.log(powerOfThree(10)); // 59049

这里返回的那个函数不需要命名,它可以在powersOf()函数外的任何地方使用,这就是匿名函数。

还记得累加器的那个函数吗?它可以用匿名函数重写

var obj1 = { value: 1 }, obj2 = { value: 2 }, obj3 = { value: 3 }; var values = (function() { // 匿名函数 var values = []; return function(obj) { // 有一个匿名函数! if (obj) { values.push(obj.value); return values; } else { return values; } } })(); // 让它自执行 console.log(values(obj1)); // Returns: [obj.value] console.log(values(obj2)); // Returns: [obj.value, obj2.value] obj1 = { value: 1 } obj2 = { value: 2 } obj3 = { value: 3 } values = do -> valueList = [] (obj) -> valueList.push obj.value if obj valueList console.log(values(obj1)); # Returns: [obj.value] console.log(values(obj2)); # Returns: [obj.value, obj2.value]

真棒!一个高阶匿名纯函数。我们怎么这么幸运?实际上还不止这些,这里面还有个自执行的结构, (function(){...})();。函数后面跟的那个括号可以让函数立即执行。在上面的例子里, 给外面values赋的值是函数执行的结果。

匿名函数不仅仅是语法糖,他们是lambda演算的化身。请听我说下去…… lambda演算早在计算机和计算机语言被发明的很久以前就出现了。它只是个研究函数的数学概念。 非同寻常的是,尽管它只定义了三种表达式:变量引用,函数调用和匿名函数,但它被发现是图灵完整的。 如今,lambda演算处于所有函数式语言的核心,包括javascript。
 由于这个原因,匿名函数往往被称作lambda表达式。

匿名函数也有一个缺点,那就是他们在调用栈中难以被识别,这会对调试造成一些困难。要小心使用匿名函数。

方法链

在Javascript中,把方法链在一起很常见。如果你使用过jQuery,你应该用过这种技巧。它有时也被叫做“建造者模式”。

这种技术用于简化多个函数依次应用于一个对象的代码。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wggwwz.html