携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第2天,点击查看活动详情
对学过的知识进行二次学习,不仅能够复习学过的知识,还可能有不可思议的收获。
隐式函数参数
在函数中,除了在函数定义中显式声明的参数之外,函数调用会传递两个隐式的参数:arguments 和 this
这些隐式参数在函数声明中没有明确定义,但会默认传递给函数并且可以在函数内正常访问。在函数内可以像其他明确定义的参数一样引用它们。
arguments参数
无论是否有明确定义对应的形参,通过它我们都可以访问到函数的所有参数。借此可以实现 原生 JavaScript 并不支持的函数重载特性,而且可以实现接收参数数量可变的可变函数。
arguments对象有一个名为length的属性,表示实参的确切个数。
function whatever(a, b, c) {
console.log(arguments)
}
whatever(1, 2, 3, 4, 5) // 传递 5 个参数
注意:
-
arguments对象的主要作用是允许我们访问传递给函数的所有参数,即便部分参数没有和函数的形参关联也无妨。 -
arguments对象仅是一个类数组的结构,避免把arguments参数当作 数组
实现一个求和函数,来计算任意数量参数的和
/**
* 使用arguments参数对所有函数参数执行操作
* @returns {T}
*/
function sum() {
// 将 arguments 转化成数组
const arr = Array.prototype.slice.call(arguments)
return arr.reduce((a, b) => {
return a + b
}, 0)
}
console.log(sum(1,2,3,4,5,6))
console.log(sum(1,2,3,4))
this 函数上下文
函数调用
function foo(name) {}
function bar(name) {}
foo('john')
(function (who) {
return who
})('hello')
const hehe = {
foo1: function (){}
}
hehe.foo1('123') // 对象的方法 调用
hehe = new bar('bar') // 作为构造函数调用
foo.call(hehe, 'hehe') // 通过call方法调用
foo.apply(hehe, ['hehe']) // 通过apply方法调用
1. 作为函数被调用
什么是作为函数被调用?几个例子
function test1(){}
const test2 = function (){}
test1() // 函数定义被调用
test2() // 函数作为表达式被调用
(function (){})() // 立即被调用的函数
作为函数被调用时,this 指向有两种:
- 在非严格模式下,它将是全局上下文(window对象)。
- 而在严格模式下,它将是 undefined。
function test1(){
console.log(this)
}
function test2() {
"use strict";
console.log(this)
}
test1() // Window
test2() // undefined
2. 作为方法被调用
test 函数作为方法,被调用
const a = {
test: function (){
console.log(this) // { test: f }
}
}
a.test()
这种调用方式,this 指向对象。
3. 作为构造函数调用
function Test() {
this.a = function () {
return this
}
}
const b1 = new Test()
const b2 = new Test()
console.log(b1.a()) // Test {a: ƒ}
console.log(b2.a()) // Test {a: ƒ}
创建了一个名为 Test 的构造函数,通过 new 调用时候会创建一个空的对象,并将其作为函数上下文,也就是 this, 传递给函数。
整个 new 的过程:
- 创建一个新的空对象。
- 该对象作为 this 参数传递给构造函数,从而成为构造函数的函数上下文。
- (将方法属性添加到该对象)
- 新构造的对象作为 new 运算符的返回值
构造函数返回值
测试一下:
const obj1 = {
name: 'xiaoxxxxxxx'
}
function Person1() {
this.name = 'xiaoming'
return obj1
}
function Person2() {
this.name = 'xiaoming'
return 1
}
const p1 = new Person1()
console.log(p1) // {name: 'xiaoxxxxxxx'}
const p2 = new Person2()
console.log(p2) // Person2 {name: 'xiaoming'}
结论:
- 如果构造函数返回一个对象,则该对象将作为整个表达式的值返回,而传入构造函数的 this 将被丢弃。
- 但是,如果构造函数返回的是非对象类型,则忽略返回值,返回新创建的对象。
4. 使用apply和call方法调用
以上几种方法,this 指向,都存在各自的规律。
那如果想改变函数上下文怎么办呢?想要显式指定它怎么办?
例子
const obj3 = {
foo: 1
}
function bar(str1, str2) {
console.log(str1) // aaa
console.log(str2) // bbb
console.log(this.foo) // 1
console.log(this) // { foo: 1 }
}
bar.call(obj3, 'aaa', 'bbb')
bar.apply(obj3, ['aaa', 'bbb'])
可以看出它们的 作用 是改变函数执行时的 this 指向,区别就是第二个参数格式不同。