作用域
全局作用域:
不在任何函数内定义的变量就具有全局作用域。实际上,JavaScript默认有一个全局对象**window,**全局作用域的变量实际上被绑定到window的一个属性。
任何变量(函数也视为变量),如果没有在当前函数作用域中找到,就会继续往上查找,最后如果在全局作用域中也没有找到,则报ReferenceError错误。
'use strict';
var course = 'Learn JavaScript';
alert(course); // 'Learn JavaScript'
alert(window.course); // 'Learn JavaScript'
//以变量方式var foo = function () {}定义的函数实际上也是一个全局变量,因此,顶层函数的定义也被视为一个全局变量,并绑定到window对象:
function foo() {
alert('foo');
}
foo(); // 直接调用foo()
window.foo(); // 通过window.foo()调用
函数作用域: 无块级作用域,在for循环等语句块中是无法定义具有局部作用域的变量
ES6引入了新的关键字let,用let替代var可以申明一个块级作用域的变量:
function foo() {
var sum = 0;
for (let i=0; i<100; i++) {
sum += i;
}
i += 1; // SyntaxError
}
名字空间:把自己的所有变量和函数全部绑定到一个全局变量中 var jQuery={},采用 jQuery.func() 进行引用。
函数中的this关键字(在对象中绑定的函数,成为这个对象的方法)
坑一:在对象外部定义函数,在内部把该函数赋值给函数,直接调用函数,this找不到对象,以对象的方法调用,this为当前对象。
//作为函数(非绑定对象),内部this指向全局对象 window
function getAge() {
var y = new Date().getFullYear();
return y - this.birth;
}
var xiaoming = {
name: '小明',
birth: 1990,
age: getAge
};
xiaoming.age(); // 25, 正常结果
getAge(); // NaN
坑二:先拿到对象的函数,再进行调用也会报错
//要保证this指向正确,必须用obj.xxx()的形式调用!
var fn = xiaoming.age; // 先拿到xiaoming的age函数
fn(); // NaN
坑三:在函数内部定义的函数,并不能和对象绑定,this又指向undefined
RE:常用解决方法 — var that = this; 在方法内部捕获对象,之后再使用.
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
//就可以放心地在方法内部定义其他函数,而不是把所有语句都堆到一个方法中。
用 apply 关键字绑定函数的 this 指向对象,并传递包装成 array的参数数组
(1) 装饰器: 动态改变原函数的行为
var count = 0;
var oldParseInt = parseInt; // 保存原函数
window.parseInt = function () {
count += 1;
return oldParseInt.apply(null, arguments); // 调用原函数(传递原参数)
};
// 测试:
parseInt('10');
parseInt('20');
parseInt('30');
count; // 3
(2) 绑定函数对象
getAge.apply(xiaoming,[])
//第一个参数为需要绑定的this变量,第二个参数为函数本身的参数数组Array.
- 用 call 关键字绑定对象,并且把参数按顺序传入,与 apply 类似。
Math.max.apply(null, [3, 5, 4]); // 5
Math.max.call(null, 3, 5, 4); // 5
//对普通函数调用,我们通常把this绑定为null。
参数:arguments:
它只在函数内部起作用,并且永远指向当前函数的调用者传入的所有参数。arguments类似Array但它不是一个Array
//如果abs(x)函数的参数x未定义将收到undefined,计算结果为NaN。
//要避免收到undefined,可以对参数进行检查:
function abs(x) {
if (typeof x !== 'number') {
throw 'Not a number';
}
if (x >= 0) {
return x;
} else {
return -x;
}
}
参数:rest: ES6标准引入,将剩余参数组成新数组
'use strict';
function sum(...rest) {
var sum = 0
for(i=0;i<rest.length;i++)
{
sum +=rest[i]
}
return sum;
}
//用来当做可变参数函数的输入参数
var i, args = [];
for (i=1; i<=100; i++) {
args.push(i);
}
if (sum() !== 0) {
alert('测试失败: sum() = ' + sum());
} else if (sum(1) !== 1) {
alert('测试失败: sum(1) = ' + sum(1));
} else if (sum(2, 3) !== 5) {
alert('测试失败: sum(2, 3) = ' + sum(2, 3));
} else if (sum.apply(null, args) !== 5050) {
alert('测试失败: sum(1, 2, 3, ..., 100) = ' + sum.apply(null, args));
} else {
alert('测试通过!');
}