- 函数中两个隐含的参数:arguments 和 this
- 调用函数的不同方式
- 处理函数上下文的问题
使用 arguments 参数对所有函数参数执行操作
function sum() {
var sum = 0;
for (var i = 0; i < arguments.length; i++) {
sum += arguments[i];
}
return sum;
}
在大多数情况下可以使用剩余参数(rest parameter)来代替
arguments
参数。剩余参数是真正的Array
实例,也就是说你可以在它上面直接使用所有的数组方法。这点相对于arguments
对象而言是个优势。
4 种方式调用一个函数,每种方式之间有一些细微差别。
- 作为一个函数(function)——
skulk()
,直接被调用。- 当以这种方式调用时,函数上下文(
this
关键字的值)有两种可能性:在非严格模式下,它将是全局上下文(window
对象),而在严格模式下,它将是undefined
。
- 当以这种方式调用时,函数上下文(
- 作为一个方法(method)——
ninja.skulk()
,关联在一个对象上,实现面向对象编程。- 当函数作为某个对象的方法被调用时,
this
对象会成为函数的上下文,并且在函数内部可以通过参数访问到。
- 当函数作为某个对象的方法被调用时,
- 作为一个构造函数(constructor)——
new Ninja()
,实例化一个新的对象。- 使用关键字 new 调用函数会触发以下几个动作。
- 创建一个新的空对象。
- 该对象作为 this 参数传递给构造函数,从而成为构造函数的函数上下文。
- 新构造的对象作为 new 运算符的返回值(除了我们很快要提到的情况之外)。
- 小结
- 如果构造函数返回一个对象,则该对象将作为整个表达式的值返回,而传入构造函数的 this 将被丢弃。
- 但是,如果构造函数返回的是非对象类型,则忽略返回值,返回新创建的对象。
- 使用关键字 new 调用函数会触发以下几个动作。
- 通过函数的 apply 或者 call 方法——
skulk.apply(ninja)
或者skulk.call(ninja)
。
function skulk(name) {}
function Ninja(name) {}
skulk('Hattori');
(function(who) {
return who;
})('Hattori'); // 作为函数调用
var ninja = {
skulk: function() {}
};
ninja.skulk('Hattori'); // 作为 ninja 对象的一个方法调用
ninja = new Ninja('Hattori'); // 作为构造函数调用
skulk.call(ninja, 'Hattori'); // 通过 call 方法调用
skulk.apply(ninja, ['Hattori']); // 通过 apply 方法调用
构造函数返回值
- 返回原始值的构造函数
function Ninja() {
this.skulk = function() {
return true;
};
return 1;
}
console.log(Ninja() === 1) // true
var ninja = new Ninja();
console.log(typeof ninja === "object") // true
console.log(typeof ninja.skulk === "function") // true
- 显式返回对象值的构造函数
var puppet = {
rules: false
};
function Emperor() {
this.rules = true;
return puppet;
}
var emperor = new Emperor();
console.log(emperor === puppet) // true
console.log(emperor.rules === false) // true
测试结果表明,puppet
对象最终作为构造函数调用的返回值,而且在构造函数中对函数上下文的操作都是无效的。最终返回的将是 puppet
。
- 如果构造函数返回一个对象,则该对象将作为整个表达式的值返回,而传入构造函数的 this 将被丢弃。
- 但是,如果构造函数返回的是非对象类型,则忽略返回值,返回新创建的对象。
- 使用箭头函数绕过函数上下文
- 调用箭头函数时,不会隐式传入 this 参数,而是从定义时的函数继承上下文。
- 当调用函数时,除了传入在函数定义中显式声明的参数之外,同时还传入两个隐式参数:
arguments
与this
。- arguments 参数是传入函数的所有参数的集合。具有
length
属性,表示传入参数的个数,通过arguments
参数还可获取那些与函数形参不匹配的参数。 在非严格模式下,arguments
对象是函数参数的别名,修改arguments
对象 会修改函数实参,可以通过严格模式避免修改函数实参。 this
表示函数上下文,即与函数调用相关联的对象。函数的定义方式和调用方式决定了 this 的取值。
- arguments 参数是传入函数的所有参数的集合。具有
- 函数的调用方式有 4 种。
- 作为函数调用:
skulk()
。 - 作为方法调用:
ninja.skulk()
。 - 作为构造函数调用:
new Ninja()
。 - 通过
apply
与call
方法调用:skulk.apply(ninja)
或skulk.call(ninja)
。
- 作为函数调用:
- 函数的调用方式影响
this
的取值。- 如果作为函数调用,在非严格模式下,
this
指向全局window
对象;在严格模式下,this
指向undefined
。 - 作为方法调用,
this
通常指向调用的对。 - 作为构造函数调用,
this
指向新创建的对象。 - 通过
call
或apply
调用,this
指向call
或apply
的第一个参数。
- 如果作为函数调用,在非严格模式下,
- 箭头函数没有单独的
this
值,this
在箭头函数创建时确定。 - 所有函数均可使用
bind
方法,创建新函数,并绑定到bind
方法传入的参数上。被绑定的函数与原始函数具有一致的行为。