函数式 JavaScript 教程(一)-阿里云开发者社区

开发者社区> 玄学酱> 正文

函数式 JavaScript 教程(一)

简介: 本文讲的是函数式 JavaScript 教程(一),本文是介绍 JavaScript 函数式编程的四部分之首篇。在这篇文章里,我们来看一下那些让 JavaScript 适合作为函数式编程语言的组成部分,并探讨为什么函数式编程可能是有用的。
+关注继续查看
本文讲的是函数式 JavaScript 教程(一),

本文是介绍 JavaScript 函数式编程的四部分之首篇。在这篇文章里,我们来看一下那些让 JavaScript 适合作为函数式编程语言的组成部分,并探讨为什么函数式编程可能是有用的。

什么是函数?

函数式 JavaScript 因为什么而热门?为什么称之为_函数式_?那应该也不是任何一个选择写不良的或者非函数式js的人选择写它们的原因,函数式编程适合用在什么地方?为什么你会感到困扰?

对于我而言,学习函数式编程有点像 得到了一个全能料理机:

  • 它需要一点前期的学习成本;
  • 之后你会开始告诉你的朋友和亲人们它有多酷炫;
  • 他们会开始怀疑你是不是加入了某种邪教。

但是,函数式编程确实让某些任务变得轻松很多,它甚至可以自动化某些本来是无聊耗时的工作。

组成部分

在进入正题之前,我们先介绍一下 JavaScript 的那些让函数式编程成为可能的基本特征。在 JavaScript 中,有两个关键的组成部分:变量 和 函数。变量有点像容器,我们可以把内容放进去,比如你可以这样写:

var myContainer = "Hey everybody! Come see how good I look!";

这句话创建了一个名为 myContainer 的容器,并把一个字符串放了进去。

现在来看看函数,函数是一种封装若干指令,使其便于重复利用的方式;也可以理解为把若干事情先组织起来,使你不必立即想清楚一切。我们可以创建一个像这样的函数:

function log(someVariable) {
    console.log(someVariable);
    return someVariable;
}

然后这样调用:

log(myContainer);
// Hey everybody! Come see how good I look!

如果你熟悉 JavaScript,应该还知道我们可以像这样定义和调用函数:

var log = function(someVariable) {
    console.log(someVariable);
    return someVariable;
}

log(myContainer);
// Hey everybody! Come see how good I look!

认真观察下,当我们以这种方式定义函数时,看起来就像定义了一个 log 变量,并且把函数放进了这个变量,而这正是我们所做的。我们的 log() 函数确实是一个变量,这意味着我们可以对它做与其它变量一样的事情。

让我们试一试,能否把函数作为参数,传递给另一函数呢?

var classyMessage = function() {
    return "Stay classy San Diego!";
}

log(classyMessage);
// [Function]

嗯,这太小儿科了,换个花样试试:

var doSomething = function(thing) {
    thing();
}

var sayBigDeal = function() {
    var message = "I'm kind of a big deal";
    log(message);
}

doSomething(sayBigDeal);
// I'm kind of a big deal

现在你可能觉得这个结果没什么特别的,但对于计算机科学家而言就非常兴奋了。这种把函数放进变量的特性,有时候会被称为 “函数是 JavaScript 的一等公民” (functions are first class objects in JavaScript.)。这意味着大部分时候,可以把函数和其他数据类型(比如对象或字符串)等同对待。这个看起来小的特征可是相当的强大,不过在理解原因之前,我们需要先来介绍一下 DRY 原则。

不要重复你自己

程序员都喜欢提及 DRY 原则 - 不要重复你自己(Don't Repeat Yourself)。其思想就是,如果你需要多次进行相同的工作,那就把它们打包起来,放入到某种可重用的包装里(比如函数)。通过这种方式,一旦想要调整那个任务集,你就只需要改动一个地方。

看这个例子,我们使用了一个轮播库,创建三个轮播组件,并放到页面中:

var el1 = document.getElementById('main-carousel');
var slider1 = new Carousel(el1, 3000);
slider1.init();

var el2 = document.getElementById('news-carousel');
var slider2 = new Carousel(el1, 5000);
slider2.init();

var el3 = document.getElementById('events-carousel');
var slider3 = new Carousel(el3, 7000);
slider3.init();

这段代码看起来有点重复,我们想要初始化页面中的轮播组件,而每个组件有一个特定的 ID。因此,让我们看看如何在一个函数中初始化轮播组件,并且为每一个组件 ID 调用该函数:

function initialiseCarousel(id, frequency) {
    var el = document.getElementById(id);
    var slider = new Carousel(el, frequency);
    slider.init();
    return slider;
}

initialiseCarousel('main-carousel', 3000);
initialiseCarousel('news-carousel', 5000);
initialiseCarousel('events-carousel', 7000);

这段代码更加清晰和易于维护。我们需要遵循一个模式:当我们想要对不同的数据集合进行相同的操作时,只需把这些操作包装进函数中。但是,如果我们进行的操作不尽相同呢?

var unicornEl = document.getElementById('unicorn');
unicornEl.className += ' magic';
spin(unicornEl);

var fairyEl = document.getElementById('fairy');
fairyEl.className += ' magic';
sparkle(fairyEl);

var kittenEl = document.getElementById('kitten');
kittenEl.className += ' magic';
rainbowTrail(kittenEl);

要重构这段代码就有一点棘手了,代码当中肯定有重复的行为,但是也为每个元素调用了不同的函数。我们可以把调用document.getElementById() 和添加 className 打包到一个函数中,这样可以降低一点重复度:

function addMagicClass(id) {
    var element = document.getElementById(id);
    element.className += ' magic';
    return element;
}

var unicornEl = addMagicClass('unicorn');
spin(unicornEl);

var fairyEl = addMagicClass('fairy');
sparkle(fairyEl);

var kittenEl = addMagicClass('kitten');
rainbow(kittenEl);

但我们还能让代码更加 DRY,还记得 JavaScript 可以把函数作为参数传递给其它函数吗?

function addMagic(id, effect) {
    var element = document.getElementById(id);
    element.className += ' magic';
    effect(element);
}

addMagic('unicorn', spin);
addMagic('fairy', sparkle);
addMagic('kitten', rainbow);

这段代码就简洁多了,也更易于维护。这种把函数作为变量并传递给另一函数的能力,为我们的代码提供了更多可能性。在下一节,我们会试着在数组中运用这种能力,让数组变得更加方便使用。





原文发布时间为:2016年04月20日

本文来自云栖社区合作伙伴掘金,了解相关信息可以关注掘金网站。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
SharpDX之Direct2D教程II——加载位图文件和保存位图文件
本系列文章目录: SharpDX之Direct2D教程I——简单示例和Color(颜色)   绘制位图是绘制操作的不可缺少的一部分。在Direct2D中绘制位图,必须先利用WIC组件将位图加载到内存中,再绘制到RenderTarget中去   在SharpDX中绘制位图,分成两个部分: ...
839 0
后端开发必备JavaScript函数
0 全局对象 decodeURIComponent() 定义和用法 decodeURIComponent() 函数可对 encodeURIComponent() 函数编码的 URI 进行解码。
707 0
Shell常用命令教程
1.打印当前目录 命令:pwd pwd命令图示.png 2.获取当前计算机的名称 命令:hostname hostname命令图示.png Win10修改计算机名称的方法: 修改计算机名称1.png 修改计算机名称2.png 修改计算机名称3.png 完成上面3步之后,多次点击确定并重启电脑就可以完成修改计算机名。
828 0
WireShark教程之捕捉时过滤案例
Wireshark使用libpcap过滤语句进行捕捉过滤(what about winpcap?)。在tcpdump主页有介绍,但这些只是过于晦涩难懂,所以这里做小幅度讲解。 提示 你可以从http://wiki.
783 0
JavaScript立即调用的函数表达式
主要参考知乎上这个问题:javascript 匿名函数有哪几种执行方式  长天之云的回答。 ~(function() {//todo})();!(function() {//todo})(); 对于不太熟悉JavaScript的同学来讲,可能会有两个疑问: 1、!(function() {})();前面为什么要加~、!这些符号? 后面的()是执行一个函数,而(function() {})是一个执行表达式,返回一个匿名函数的引用。
607 0
教程: Ext 2.0 介绍
本教程适用于Ext 2.0的版本,而版本1.x仍可找到。 无论你是Ext库的新手,抑或是想了解Ext的人,本篇文章的内容都适合你。本文将简单地介绍Ext的几个基本概念,和如何快速地做出一个动态的页面并运行起来,假设读者已具备了一些JavaScript经验和简单了解HTML的文档对象模型(document object model ,DOM)。
873 0
JavaScript 函数
函数是由事件驱动的或者当它被调用时执行的可重复使用的代码块。 # JavaScript 函数语法 函数就是包裹在花括号中的代码块,前面使用了关键词 function:function functionname() { 执行代码 } 当调用该函数时,会执行函数内的代码。
1288 0
javascript 表达式、括号、常用函数和jquery库怎么样实现的分析
(一)javascript表达式 表达式是什么?表达式是对变更进行赋值、更改或计算等操作的语句。它是变量、常量、操作符的综合。根据操作符的不类型,可以分为字符操作表达式、赋值表达式、逻辑表达式、关系表达式、自增自减表达式、位表达式等。
724 0
+关注
玄学酱
这个时候,玄酱是不是应该说点什么...
20710
文章
438
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载