《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调用函数会触发以下几个动作:
- 创建一个新的空对象。
- 该对象作为this参数传递给构造函数,从而成为构造函数的函数上下文。
- 默认新构造的对象作为new运算符的返回值。
- 如果构造函数返回一个对象,则该对象将作为整个表达式的值返回,而传入构造函数的this将被丢弃。
- 但是,如果构造函数返回的是非对象类型,则忽略返回值,返回新创建的对象。
-
编写构造函数的注意事项
命名:
构造函数名用大写开头的名词,如: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 解决函数上下文的问题
-
箭头函数
-
使用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
```