My JavaScript Notes
1. 作用域问题
1)隐式全局变量声明
function func1() { var a1 = b1 = 1; return b1; } func1(); console.log(b1); function func2() { var a2 = b2 = 2; return a2; } func2(); console.log(a2);
以上输出的结果分别是"1"和"null"(或"a2 is not defined"),乍一看觉得匪夷所思,但是了解了JS的作用域知识以后,迎刃而解:
用var声明后,a1是func1的本地变量,而中间变量b1没有被声明地直接拿来使用,相当于创造了一个全局变量。本地变量在外部作用域中无法访问是几乎所有编程语言共同的,而根据JS闭包原则,全局变量b1则可以被访问到。
2) 变量提升
JavaScript的函数定义有个特点,它会先扫描整个函数体的语句,把所有申明的变量“提升”到函数顶部:但是只提升函数的声明,不提升赋值。
例如:
'use strict'; function foo() { var x = 'Hello, ' + y; alert(x); var y = 'Bob'; } foo();
在引擎看来相当于:
function foo() { var y; // 提升变量y的申明 var x = 'Hello, ' + y; alert(x); y = 'Bob'; }
函数声明的变量名字和值都会提升,而函数表达式只提升名字,例如:
a(); b(); function a(){ //.... } var b = function () { //.... }
a()能正常调用,而b()会报错。其实并非任何特殊规则作怪,只是因为第一种会先加载,不管函数调用的先后,而第二种,只有在给b赋值的时候才去加载那个函数,然后赋值给b变量。
2. 匿名函数与闭包
1) 箭头函数
箭头函数看上去是匿名函数的一种简写,但实际上,箭头函数和匿名函数有个明显的区别:箭头函数内部的this是词法作用域,由上下文确定。
由于JavaScript函数对this绑定的错误处理,下面的例子无法得到预期结果:
var obj = { birth: 1990, getAge: function () { var b = this.birth; // 1990 var fn = function () { return new Date().getFullYear() - this.birth; // this指向window或undefined }; //var fn = () => new Date().getFullYear() - this.birth; // this指向obj对象 return fn(); } };
用箭头函数改写上述obj,把fn的定义换成下面注释的那行。现在,箭头函数完全修复了this的指向,this总是指向词法作用域,也就是外层调用者obj:obj.getAge(); // 25
.
如果使用箭头函数,以前的那种hack写法:var that = this;
就不再需要了。
另外,由于this在箭头函数中已经按照词法作用域绑定了,所以,用call()
或者apply()
调用箭头函数时,无法对this进行绑定,即传入的第一个参数被忽略:
var obj = { birth: 1990, getAge: function (year) { var b = this.birth; // 1990 var fn = (y) => y - this.birth; // this.birth仍是1990 return fn.call({birth:2000}, year); } }; obj.getAge(2015); // 25