数据结构
ES6引入了新的数据类型,Map
Set
等.
Map
同Java Map定义,也是一组键值对结构,查找速度快。
Map的操作:
- 定义。
var m = new Map([['Michael', 95], ['Bob', 75], ['Tracy', 85]]);
- 增,
m.set('Adam', 67)
添加新的key-value - 删,
m.delete('Adam')
删除key ‘Adam’ - 改,
m.set('Bob', 59)
修改 - 查,
m.has('Adam')
判断是否存在,m.get('Adam')
查询key对应的值
Set
Set
同Java,一组key的集合,但不存储value, key不能重复.
- 定义。
var s = new Set([1, 2, 3, 4]);
- 增,
s.add(5)
添加元素到Set
中 - 删,
s.delete(3)
删除元素3 - 改,
Set
没有改的概念. - 查,
s.has(3)
查找是否存在3这个元素.
iterabale的遍历
Array
Map
Set
都是iterable类型。
- 使用
for ... of
遍历,对于Array
也支持for ... in
, 当Array元素被当作属性值添加使用时,两者有区别,for ... of
更符合常规。
var a = ['A', 'B', 'C'];
var s = new Set(['A', 'B', 'C']);
var m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]);
for (var x of a) { // 遍历Array
console.log(x);
}
for (var x of s) { // 遍历Set
console.log(x);
}
for (var x of m) { // 遍历Map
console.log(x[0] + '=' + x[1]);
}
- 使用
iterable
的方法forEach
进行遍历.
forEach
参数为一个函数。使用如下,
var a = ['A', 'B', 'C'];
a.forEach(function (element, index, array) {
// element: 指向当前元素的值
// index: 指向当前索引
// array: 指向Array对象本身
console.log(element + ', index = ' + index+ ', a='+array);
});
var s = new Set(['A', 'B', 'C']);
s.forEach(function (element, sameElement, set) {
// Set没有位置的概念,所以第二个参数为 sameElement,与前一个相同
console.log(element);
});
var m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]);
m.forEach(function (value, key, map) {
// 同理,value相当于值,key相当于位置
console.log('value='+value+', key='+key);
});
函数
JavaScript函数形式上,跟Java有些不同,没有返回值声明
,变量类型声明
。而且JS中的函数可以像变量一样使用,具有强大的抽象能力。
函数调用对参数匹配也不需要一一对应
,例如 可以少于定义声明。
JavaScript有一个参数关键字arguments
, 它只在函数内部起作用。使用方法跟Array
一样,但它不是Array
注意:JS函数没那么严格
ES6标准引入了rest参数,表示剩余参数的意思。格式function foo(a, b, ...rest) {}
,rest是一个数组,在这里表示第2个参数以后的参数,如果参数个数<=2
rest为一个空数组,注意不是null
格式如下:
//函数定义,使用 function 表明是一个函数,参数部分只需要写参数名
function abs(x) {
if (x >= 0) {
return x;
} else {
return -x;
}
}
//匿名函数,没有函数名
var abs = function (x) {
if (x >= 0) {
return x;
} else {
return -x;
}
};
//以上,两者的方式是一样的
function sum(...rest) {
//注意rest不会为null
var sum = 0;
for(var i=0; i<rest.length; i++) {
sum += rest[i];
}
return sum;
}
变量作用域
变量的作用域同 java,需要注意的是JavaScripte默认有一个全局对象window
,例如常用的alert()
都是window
的变量。
任何变量(函数也视为变量),如果没有在当前函数作用域中找到,就会继续往上查找,最后如果在全局作用域中也没有找到,才报错。
不同的JavaScript文件如果使用了相同的全局变量,或者定义了相同名字的顶层函数,都会造成命名冲突,难以发现。为了减少冲突,可以把自己的所有变量和函数全部绑定到一个全局变量中。起到命名空间
的效果,常见的jQuery, YUI, underscore等也是这样实现的,参考示例,
// 唯一的全局变量MYAPP:
var MYAPP = {};
// 其他变量:
MYAPP.name = 'myapp';
MYAPP.version = 1.0;
// 其他函数:
MYAPP.foo = function () {
return 'foo';
};
ES6引入了关键字let
, 为了解决块级作用域的问题,如下,
function foo() {
var sum = 0;
//如果使用 var,作用域为整个函数
for (let i=0; i<100; i++) {
sum += i;
}
// SyntaxError:
i += 1;
}
解构赋值
从ES6开始支持解构赋值
,作用,批量定义变量,并赋值
。参考示例,
//传统的赋值
var array = ['hello', 'JavaScript', 'ES6'];
var x = array[0];
var y = array[1];
var z = array[2];
//解构赋值
var [x, y, z] = ['hello', 'JavaScript', 'ES6'];
//以上达到的效果一样
另外,解构赋值也支持对象,使用{...}
来对应。使用场景,
//1. 交换两个变量的值
var x=1, y=2;
[x, y] = [y, x]
//2. 用作参数,减少代码量
//hour, minute, second有默认值
function buildDate({year, month, day, hour=0, minute=0, second=0}) {
return new Date(year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second);
}
buildDate({ year: 2017, month: 1, day: 1 }); // 使用1
buildDate({ year: 2017, month: 1, day: 1, hour: 20, minute: 15 }); //使用2
this
类似于java的this指针
,都是用来指向当前对象的,但是在JS中this不能省略(跟java不同),xiaoming.age()
age方法中的this
为xiaoming.
要保证this
指向正确,尽量用obj.xxx()
形式调用。
var xiaoming = {
name: '小明',
birth: 1990,
age: function () {
var y = new Date().getFullYear();
return y - this.birth; //this不能省略
}
};
xiaoming.age; //这是一个方法
xiaoming.age(); //29
可通过apply(obj, array)
指定this
, 其中obj指定this对象,array 为参数。
使用上相当于Java中的反射
,例如,
function getAge() {
var y = new Date().getFullYear();
return y - this.birth;
}
var xiaoming = {
name: '小明',
birth: 1990,
age: getAge
};
xiaoming.age(); // 29
getAge.apply(xiaoming, []); // 29, this指向xiaoming, 参数为空
//也可以用 getAge.call(xiaoming);
另外,还有一个关键字call
作用跟apply
一样, 只不过call
不用封装数据,把参数按顺序传入。