第四章 函数进阶:理解函数调用 | 《JavaScript忍者秘籍》学习笔记

151 阅读2分钟

《JavaScript忍者秘籍(第二版)》学习笔记

4.1 隐式函数参数

4.1.1 arguments

arguments是实参,实参就是实际传给函数的参数,形参是函数一开始定义的参数

💡 arguments不是数组

arguments可以作为函数参数的别名,会改变形参的值:

Fn('Debra')

function Fn(name) {
console.log(name) // Debra
arguments[0] = 'Debbie'
console.log(name) // Debbie
}

反之亦然:

Fn('Debra')

function Fn(name) {
console.log(arguments[0]) // Debra
name = 'Debbie'
console.log(arguments[0]) // Debbie
}
💡 但是不提倡使用,严格模式不能作为别名用

4.1.2 this参数:函数上下文

4.2 函数调用

4.2.1 直接调用

this指向window

4.2.2 作为方法被调用(面向对象编程)

谁调用的,this就指向谁

4.2.3 作为构造函数调用

  • 使用关键字new调用函数会触发以下几个动作:

    1. 创建一个新的空对象。
    2. 该对象作为this参数传递给构造函数,从而成为构造函数的函数上下文。
    3. 默认新构造的对象作为new运算符的返回值。
    4. 如果构造函数返回一个对象,则该对象将作为整个表达式的值返回,而传入构造函数的this将被丢弃。
    5. 但是,如果构造函数返回的是非对象类型,则忽略返回值,返回新创建的对象。
  • 编写构造函数的注意事项

    命名:

    构造函数名用大写开头的名词,如:Person、Supermarket...
    
    构造函数中的方法用小写开头的动词命名:如,takePhoto, sleep, buyStuff...
    

4.2.4 使用apply和call方法调用

apply和call都可以改变this

function sum() {
return [...arguments].reduce((prev, curr) => {
return prev + curr
})
}

const ninja1 = {}
const ninja2 = {}
console.log(sum.apply(ninja1, [1, 2, 3, 4]))
console.log(sum.call(ninja2, 1, 2, 3, 4))

区别在于:apply的第二个参数要传数组,而call传的是参数。bind用法和call一样,区别在于bind不会直接调用,需要自己手动再调用。

4.3 解决函数上下文的问题

  1. 箭头函数

  2. 使用bind

练习

```jsx
const ninja1 = {
  whoAmI: function() {
    return this
  }
}
const ninja2 = {
  whoAmI: ninja1.whoAmI
}
const id = ninja2.whoAmI

ninja1.whoAmI() === ninja1 // true ninja1调用,指向ninja1
ninja2.whoAmI() === ninja1 // false 因为是ninja2调用,就指向ninja2
id() === ninja1 // false id也是ninja2调用的,指向ninja2
ninja1.whoAmI.call(ninja2) === ninja2 // true,通过call来改变this指向到ninja2
```
```jsx
function Ninja() {
  this.me = () => this
}

const ninja1 = new Ninja()
const ninja2 = {
  me: ninja1.me
}

ninja1.me() === ninja1 // true 箭头函数指向自己内部的上下文
ninja2.me() === ninja2 // false 箭头函数指向自己内部的上下文
```
```jsx
function Ninja() {
  this.me = function() {
    return this
  }.bind(this)
}

const ninja1 = new Ninja()
const ninja2 = {
  me: ninja1.me
}

// 通过bind改变了this指向
ninja1.me() === ninja1 // true 
ninja2.me() === ninja2 // false
```