闭包作用域与调用环境问题

之前做相册的后台监控系统,在编写前端ajax请求数据批量更新界面的代码时,遇到了在循环体中构造闭包的一个常见问题。现记录如下。

系统中的case抽象出来就是这样一个问题:定义一个函数,这个函数返回一个长度为4的函数数组,且第i个函数的调用结果是在屏幕上打印数字i。

初步一想,这个问题很简单,代码如下:

function echo_funcs() {
  var funcs = []; 
  for (var i = 1; i < 5; ++i) {
    function echo_func() {
      console.log(i);      // 第i个函数打印i
    }   
    funcs.push(echo_func);
  }
  return funcs;
}

var funcs = echo_funcs();
for (var i in funcs) {
  funcs[i]();
}

用node.js执行这段代码,结果是:

5
5
5
5

Read More

Bash高级编程:分支和循环

list

一个list是指一个或多个命令的序列,它们以分号、&符号、控制操作符、换行来分隔,且最后一条命令的退出码就是整个list的退出码。list可以用于if, while, until等分支循环语句的条件或者执行体。

一、if

if语句的形式为:

if <condition list>
then
    <list>
fi
# 或者
if <condition list>; then <list>; fi

Read More

Bash高级编程:变量

一、变量扩展

在Bsh和兼容它的shell中,以下的变量扩展形式根据变量的存在性、非空性进行条件扩展

${var-default}   # 若 var 不存在则扩展为 default,否则扩展为 $var
${var:-default}  # 同上,但当 var 为空时,处理与不存在相同

${var+alter}     # 若 var 存在则扩展为 alter,否则扩展为 $var
${var:+alter}    # 同上,但当 var 为空时,处理与不存在相同

${var=default}   # 与 ${var-default} 相同,且 var 会被赋值
${var:=default}  # 同上,但当 var 为空时,处理与不存在相同

${var?message}   # 若 var 不存在则打印 message 信息并以状态码 1 来终止脚本
${var:?message}  # 同上,但当 var 为空时,处理与不存在相同

Read More

Bash高级编程:命令行扩展

引号:

Shell首先会根据IFS变量把命令行中未被引号引入的部分拆分成一个个word(IFS默认为空格、制表符、换行)。若空格被\转义,则会被视为一个word中的一部分。

双引号中可以随意包含单引号,单引号中也可以随意包含双引号。但是双引号要被转义之后才能被双引号包含。而单引号中的任何字符都不会被视为特殊字符,因此单引号中没办法再包含单引号了,即使被转义。一个转义的单引号也会提前结束前面的那个单引号。若需要在单引号中包含单引号,即正确转义,则需借助语法:

echo $'hello \'world\''   # hello 'world'

一、大括号扩展(非 POSIX 标准)

未被引号引起来的大括号中,若有以逗号(,)连接的列表,或者用双点号(..)指定的范围,则会被扩展为独立的参数(逗号和双点前后都不能有空格,且逗号和双点不能同时使用):

echo {1,2,3}   # 1 2 3
echo {a..c}    # a b c

Read More

Bash高级编程:基础

一、脚本

Bash脚本由Bash能够解释的命令组成。所有的注释以#开头直到该行结尾:

echo abc          # 显示 abc
echo abc;         # 每一行后面的分号是可选的
echo a; echo b    # 在这种情况下,第一个命令后的分号不可省
echo a &          # &和;都是行结束符,但&的意思是当前命令放到后台执行
echo a &;         # 错误,&和;只能用一个
;                 # 错误,跟高级程序语言不同的是,行结束符不是可以随意添加的

使用/bin/bash script.sh命令来运行脚本不需要脚本有可执行权限。使用./script.sh来运行脚本则需要先使用chmod +x来给脚本文件增加执行权限。

如果脚本文件有执行权限,则脚本第一行以#!开头可以指明该文件运行的解释器的绝对路径,包括/bin/bash, /bin/csh, /bin/awk -F, /usr/bin/python等,甚至也可以是/bin/cat, /bin/rm等。这样的话,当使用./script.sh命令来运行该脚本时,bash会去调用脚本指定的解释器来运行该脚本。

Read More

Bash高级编程:IO重定向

一、基本重定向:>, >>, <;

>用于输出重定向,将一个命令的标准输出1重定向到一个文件路径。如果文件不存在则创建,如果文件存在则truncate。

>>用于输出重定向,将一个命令的标准输出1重定向到一个文件路径。如果文件不存在则创建,如果文件存在则append。

<用于输入重定向,将打开一个文件作为命令的标准输入0。如果文件不存在则报错。

echo xxxxx > log      # 将 xxxxx 写入到 log 文件中
cat < log             # 输出 log 文件
cat < log > log2      # 将 log 写入到 log2 中
cat < log > log       # 这将清空 log 文件
                      # 因为重定向在命令运行前由 shell 完成,
                      # 执行 cat 的时候 log 已被 truncated
cat < log2 >> log2    # 这句会无限循环,把 log2 的每一行读出来又写到 log2 末尾

Read More