Skip to content

Latest commit

 

History

History
122 lines (96 loc) · 5.14 KB

04.函数进阶:理解函数调用.md

File metadata and controls

122 lines (96 loc) · 5.14 KB

04.函数进阶:理解函数调用

  • 函数中两个隐含的参数: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 将被丢弃。
      • 但是,如果构造函数返回的是非对象类型,则忽略返回值,返回新创建的对象。
  • 通过函数的 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 参数,而是从定义时的函数继承上下文。

小结

  • 当调用函数时,除了传入在函数定义中显式声明的参数之外,同时还传入两个隐式参数: argumentsthis
    • arguments 参数是传入函数的所有参数的集合。具有 length 属性,表示传入参数的个数,通过 arguments 参数还可获取那些与函数形参不匹配的参数。 在非严格模式下,arguments 对象是函数参数的别名,修改 arguments 对象 会修改函数实参,可以通过严格模式避免修改函数实参。
    • this 表示函数上下文,即与函数调用相关联的对象。函数的定义方式和调用方式决定了 this 的取值。
  • 函数的调用方式有 4 种。
    • 作为函数调用:skulk()
    • 作为方法调用:ninja.skulk()
    • 作为构造函数调用:new Ninja()
    • 通过 applycall 方法调用:skulk.apply(ninja)skulk.call(ninja)
  • 函数的调用方式影响 this 的取值。
    • 如果作为函数调用,在非严格模式下,this 指向全局 window 对象;在严格模式下,this 指向 undefined
    • 作为方法调用,this 通常指向调用的对。
    • 作为构造函数调用,this 指向新创建的对象。
    • 通过 callapply 调用,this 指向 callapply 的第一个参数。
  • 箭头函数没有单独的 this 值,this 在箭头函数创建时确定。
  • 所有函数均可使用 bind 方法,创建新函数,并绑定到 bind 方法传入的参数上。被绑定的函数与原始函数具有一致的行为。