1.let
由javavscript的变量作用域其实是函数的内部,所以我们在for循环等语句块中是无法定义具有局部作用域的变量的;
function foo(){
for(var i=0; i<100; i++){
//
}
i += 100; //仍然可以引用变量i
}
为了解决块级作用域,ES6引入了let
function foo() {
var sum = 0;
for (let i=0; i<100; i++) {
sum += i;
}
i += 1; // SyntaxError
}
2.常量
var和let申明的都是变量,如果要申明一个常量,在ES6之前我们一般用全部大写命名的方式来表示,也只能表示,不能做实际的限制
ES6引入了新的关键字const
const PI = 3.14
PI = 3
PI;//3.14
3. this
在方法内部,this是一个特殊变量,它始终指向当前对象;
例如:
function getAge() {
var y = new Date().getFullYear();
return y - this.birth;
}
var xiaoming = {
name: '小明',
birth: 1990,
age: getAge
};
xiaoming.age(); // 25, 正常结果
getAge(); // NaN
因为调用getAge时,此时this指向全局对面window。
所以呢,应该用xiaoming.age();来调用这个方法,以对象的名义去调用。
var fn = xiaoming.age
fn(); //NaN
以上这种写法也是不行的,要想要调用正确,必须用obj.xxx();
另外,当你用以下的写法时,仍然继续报错;
'use strict';
var xiaoming = {
name: '小明',
birth: 1990,
age: function () {
function getAgeFromBirth() {
var y = new Date().getFullYear();
return y - this.birth;
}
return getAgeFromBirth();
}
};
xiaoming.age(); // Uncaught TypeError: Cannot read property 'birth' of undefined
想要解决这个问题有一个版本,就是我们先用一个that变量先去把this变量捕获出来:
'use strict';
var xiaoming = {
name: '小明',
birth: 1990,
age: function () {
var that = this; // 在方法内部一开始就捕获this
function getAgeFromBirth() {
var y = new Date().getFullYear();
return y - that.birth; // 用that而不是this
}
return getAgeFromBirth();
}
};
xiaoming.age(); // 25
用var that = this;,你就可以放心地在方法内部定义其他函数,而不是把所有语句都堆到一个方法中。
4.apply
简单来说,apply的主要作用就是用来控制this的指向的
例如:
function getAge() {
var y = new Date().getFullYear();
return y - this.birth;
}
var xiaoming = {
name: '小明',
birth: 1990,
age: getAge
};
xiaoming.age(); // 25
getAge.apply(xiaoming, []); // 25, this指向xiaoming, 参数为一个空数组
利用apply()方法,我们还可以动态改变函数的行为,js的所有对象都是动态的,即使是内置的函数,我们也可以重新指向新的函数;
例如,我们想要统计一下代码一共使用了多少次parseInt(),这个时候我们就可以用到apply来修改默认内置函数praseInt(),使得它既有转化整形的功能,还有计数功能
var count = 0;
var oldParseInt = parseInt; // 保存原函数
window.parseInt = function () {
count += 1;
return oldParseInt.apply(null, arguments); // 调用原函数
};
// 测试:
parseInt('10');
parseInt('20');
parseInt('30');
count; // 3
5.call
call和apply的用法基本一样,只是call里面传得单数没有合并为数组
Math.max.apply(null, [3, 5, 4]); // 5
Math.max.call(null, 3, 5, 4); // 5
6.高阶函数
简单来说,高阶函数就是一个函数接收另外一个函数当做参数。
map()
由于map()方法定义在JavaScript的Array中,我们调用Array的map()方法,传入我们自己的函数,就得到了一个新的Array作为结果:
function pow(x) {
return x * x;
}
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
arr.map(pow); // [1, 4, 9, 16, 25, 36, 49, 64, 81]
map()这个方法把运算过程给抽象了,只需要去遍历数组,然后运算完组成新数组即可。
Array的另外一个方法,reduce()
Array的reduce()把一个函数作用在这个Array的[x1, x2, x3...]上,这个函数必须接收两个参数,reduce()把结果继续和序列的下一个元素做累积计算,效果就是:
[x1, x2, x3, x4].reduce(f) = f(f(f(x1, x2), x3), x4)
比如Array求和:
var arr = [1, 3, 5, 7, 9];
arr.reduce(function (x, y) {
return x + y;
}); // 25
经典问题:
['1', '2', '3'].map(parseInt);
这个函数返回的结果为[1,NaN,NaN],为什么?
原因如下:
["1", "2", "3"].map(function(i, indx, array) {
parseInt(i, indx); // indx 当作 radix 传进 parseInt 了
});
因为callback 函数会被自动传入三个参数: 数组元素, 元素索引,原数组本身,穿进去之后,parseInt把indx当做第二个参数了。
执行了parseInt("1",0),parseInt("2",1),parseInt("3",2),由于parseInt(string, radix) 的参数radix必须介于2~36之间,而且字符串string中的数字不能大于radix才能正确返回数字结果值。所以输出NaN
reduce()
Array的reduce()把一个函数作用在这个Array的[x1, x2, x3...]上,这个函数必须接收两个参数,reduce()把结果继续和序列的下一个元素做累积计算:
[x1, x2, x3, x4].reduce(f) = f(f(f(x1, x2), x3), x4)
var arr = [1, 3, 5, 7, 9];
arr.reduce(function (x, y) {
return x + y;
}); // 25
filter()
和map()类似,Array的filter()也接收一个函数。和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是true还是false决定保留还是丢弃该元素。
var arr = [1, 2, 4, 5, 6, 9, 10, 15];
var r = arr.filter(function (x) {
return x % 2 !== 0;
});
r; // [1, 5, 9, 15]
Array的sort()函数是用于排序的,但是它是把所有元素先转换为string后在排序
如果要进入数字大小排序,我们可以这么写:
var arr = [1,10,2,9]
arr.sort(function(x,y){
if(x<y){
return -1;
}else(x>y){
return 1;
}
return 0;
})
如果我们想要按字母顺序来排序,我们可以这么写:
var arr = ['Google', 'apple', 'Microsoft'];
arr.sort(function (s1, s2) {
x1 = s1.toUpperCase();
x2 = s2.toUpperCase();
if (x1 < x2) {
return -1;
}
if (x1 > x2) {
return 1;
}
return 0;
}); // ['apple', 'Google', 'Microsoft']