一、函数作用域
var v = 1;
function f() {
console.log(v);
}
f() // 1
函数f内部可以读取全局变量v
function f(){
var v = 1;
}
v // ReferenceError: v is not defined
在函数内部定义的变量,外部无法读取,称为“局部变量”
var v = 1;
function f(){
var v = 2;
console.log(v);
}
f() // 2
v // 1
函数内部定义的变量,会在该作用域内覆盖同名的全局变量
var a = 1;
var x = function () {
console.log(a);
};
function f() {
var a = 2;
x();
}
f() // 1
函数本身也是一个值,也有自己的作用域,它的作用域与变量一样,就是其声明时所在的作用域,与其运行时所在的作用域无关。
总之,函数执行时所在的作用域,是定义时的作用域,而不是调用时所在的作用域。
二、函数参数
var p = 2;
function f(p) {
p = 3;
}
f(p);
p // 2
函数参数如果是原始类型的值(数值、字符串、布尔值),传递方式是传值传递。
这意味着,在函数体内修改参数值,不会影响到函数外部。
var obj = { p: 1 };
function f(o) {
o.p = 2;
}
f(obj);
obj.p // 2
如果函数参数是复合类型的值(数组、对象、其他函数),传递方式是传址传递。
也就是说,传入函数的原始值的地址,因此在函数内部修改参数,将会影响到原始值。
var f = function (one) {
console.log(arguments[0]);
console.log(arguments[1]);
console.log(arguments[2]);
}
f(1, 2, 3)
// 1
// 2
// 3
arguments对象包含了函数运行时的所有参数,arguments[0]就是第一个参数,arguments[1]就是第二个参数,以此类推。
这个对象只有在函数体内部,才可以使用。
function f() {
return arguments.length;
}
f(1, 2, 3) // 3
f(1) // 1
f() // 0
通过arguments对象的length属性,可以判断函数调用时到底带几个参数。
虽然arguments很像数组,但它是一个对象,数组专有的方法(如slice、forEach等),不能在arguments对象上直接使用。
arguments对象使用数组方法,真正的解决方法是将arguments转为真正的数组。如下
方法一:
var args = Array.prototype.slice.call(arguments);
方法二:
var args = [];
for (var i = 0; i > arguments.length; i++) {
args.push(arguments[i]);
}