定义
function abs(x)
{
//argument 所有参数的数组;rest是剩余参数数组
...
}
函数是一个对象,匿名函数赋值 `abs` 对象 可定义为:
var abs = function(x)
{
...
};
- JavaScript允许传入任意个参数而不影响调用,因此传入的参数比定义的参数多也没有问题。
- ES6引入了新的关键字let,用let替代var可以申明一个块级作用域的变量。
- 由于var和let申明的是变量,如果要申明一个常量,在ES6之前是不行的,我们通常用全部大写的变量来表示“这是一个常量,不要修改它的值”,ES6标准引入了新的关键字
const
来定义常量,const
与let
都具有块级作用域:
'use strict';
const PI = 3.14;
PI = 3; // 某些浏览器不报错,但是无效果!
PI; // 3.14
- 从ES6开始,JavaScript引入了解构赋值,可以同时对一组变量进行赋值。对数组元素进行解构赋值时,多个变量要用
[...]
括起来。
var [x, y, z] = ['hello', 'JavaScript', 'ES6'];
如果数组本身还有嵌套注意嵌套层次和位置要保持一致:let [x, [y, z]] = ['hello', ['JavaScript', 'ES6']];
解构赋值还可以忽略某些元素:let [, , z] = ['hello', 'JavaScript', 'ES6']; // 忽略前两个元素,只对z赋值第三个元素
如果需要从一个对象中取出若干属性,也可以使用解构赋值,便于快速获取对象的指定属性,变量名和属性名应保持一致,如果不一致,使用{属性名:变量名} = 对象
:
var person = {
name: '小明',
age: 20,
gender: 'male',
passport: 'G-12345678',
school: 'No.4 middle school'
};
// 把passport属性赋值给变量id:
let {name, passport:id} = person;
name; // '小明'
id; // 'G-12345678'
// 注意: passport不是变量,而是为了让变量id获得passport属性:
passport; // Uncaught ReferenceError: passport is not defined
// 如果person对象没有single属性,默认赋值为true:
var {name, single=true} = person;
交换变量值
var x=1, y=2;
[x, y] = [y, x]
高阶函数可把函数作为一个参数,还可以把函数作为结果值返回
- map
map()
方法定义在JavaScript的Array中,我们调用Array的map()
方法,传入我们自己的函数,就得到了一个新的Array作为结果
'use strict';
function pow(x) {
return x * x;
}
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
var results = arr.map(pow); // [1, 4, 9, 16, 25, 36, 49, 64, 81]
console.log(results);
- reduce Array的
reduce()
把一个函数作用在这个Array的[x1, x2, x3...]上,这个函数必须接收两个参数,reduce()
把结果继续和序列的下一个元素做累积计算,其效果就是:[x1, x2, x3, x4].reduce(f) = f(f(f(x1, x2), x3), x4)
- filter 和
map()
类似,Array的filter()
也接收一个函数。和map()
不同的是,filter()
把传入的函数依次作用于每个元素,然后根据返回值是true还是false决定保留还是丢弃该元素。把一个Array中的空字符串删掉,可以这么写:
var arr = ['A', '', 'B', null, undefined, 'C', ' '];
var r = arr.filter(function (s) {
return s && s.trim(); // 注意:IE9以下的版本没有trim()方法
});
r; // ['A', 'B', 'C']
数组去重
r = arr.filter(function (element, index, self) {
return self.indexOf(element) === index;
});
- sort JavaScript的Array的
sort()
方法就是用于排序的,字符串根据ASCII码进行排序
- 闭包 定义在一个函数内部的函数,就是能够读取其他函数内部变量的函数。将函数内部和函数外部连接起来的桥梁。
function sum(arr) {
return arr.reduce(function (x, y) {
return x + y;
});
}
sum([1, 2, 3, 4, 5]); // 15
但是,如果不需要立刻求和,而是在后面的代码中,根据需要再计算怎么办?可以不返回求和的结果,而是返回求和的函数!
function lazy_sum(arr) {
var sum = function () {
return arr.reduce(function (x, y) {
return x + y;
});
}
return sum;
}
var f = lazy_sum([1, 2, 3, 4, 5]); // function sum()
f(); //15调用函数f时,才真正计算求和的结果
我们调用lazy_sum()时,每次调用都会返回一个新的函数,即使传入相同的参数
var f1 = lazy_sum([1, 2, 3, 4, 5]);
var f2 = lazy_sum([1, 2, 3, 4, 5]);
f1 === f2; // false
注意到返回的函数在其定义内部引用了局部变量arr,
所以,当一个函数返回了一个函数后,其内部的局部变量还被新函数引用。
返回闭包时牢记的一点就是:返回函数不要引用任何循环变量,或者后续会发生变化的变量。
function count() {
var arr = [];
for (var i=1; i<=3; i++) {
arr.push(function () {
return i * i;
});
}
return arr;
}
var results = count();
var f1 = results[0];
var f2 = results[1];
var f3 = results[2];
f1(); // 16
f2(); // 16
f3(); // 16
改进版:
function count() {
var arr = [];
for (var i=1; i<=3; i++) {
arr.push((function (n) {
return function () {
return n * n;
}
})(i));
}
return arr;
}
var results = count();
var f1 = results[0];
var f2 = results[1];
var f3 = results[2];
f1(); // 1
f2(); // 4
f3(); // 9
注意这里用了一个“创建一个匿名函数并立刻执行”的语法:
(function (x) {
return x * x;
})(3); // 9
Java和C++,要在对象内部封装一个私有变量,可以用private修饰一个成员变量。
在没有class机制,只有函数的语言里,借助闭包,同样可以封装一个私有变量。我们用JavaScript创建一个计数器:
function create_counter(initial) {
var x = initial || 0;
return {
inc: function () {
x += 1;
return x;
}
}
}
var c1 = create_counter();
c1.inc(); // 1
c1.inc(); // 2
c1.inc(); // 3
- Arrow Function(箭头函数)相当于匿名函数,并且简化了函数定义:
x => x * x
相当于:function (x) { return x * x; }
还有一种可以包含多条语句,这时候就不能省略{ ... }
和return
,如果参数不是一个,就需要用括号()
括起来:
// 两个参数:
(x, y) => x * x + y * y
// 无参数:
() => 3.14
// 可变参数:
(x, y, ...rest) => {
var i, sum = x + y;
for (i=0; i ({ foo: x })`
箭头函数内部的this是词法作用域,由上下文确定。
- generator 看上去像一个函数,但可以返回多次,
generator
由function*
定义(注意多出的*号),并且,除了return
语句,还可以用yield
返回多次。
function* fib(max) {
var
t,
a = 0,
b = 1,
n = 0;
while (n < max) {
yield a;
[a, b] = [b, a + b];
n ++;
}
return;
}
var f = fib(5);
f.next(); // {value: 0, done: false}
f.next(); // {value: 1, done: false}
f.next(); // {value: 1, done: false}
f.next(); // {value: 2, done: false}
f.next(); // {value: 3, done: false}
f.next(); // {value: undefined, done: true}
`fib(5)`仅仅是创建了一个`generator`对象,还没有去执行它
调用generator对象有两个方法,一是不断地调用generator对象的next()方法,next()方法会执行generator的代码,
每次遇到yield x;就返回一个对象{value: x, done: true/false},
然后“暂停”。返回的value就是yield的返回值,done表示这个generator是否已经执行结束了.
第二个方法是直接用for ... of循环迭代generator对象,这种方式不需要我们自己判断done:
for (var x of fib(10)) {
console.log(x); // 依次输出0, 1, 1, 2, 3, ...
}