函数进阶之arguments、this

以下都出自《javaScript忍者秘籍第二版》

在函数定义中显式声明的参数之外,函数调用时还会传递两个隐式的参数:arguments this。

这些隐式参数在函数声明中没有明确定义,但会默认传递给函数并且可以在函数内正常访问。在函数内可以像其他明确定义的参数一样引用它们。接下来依次介绍这些隐式参数。


arguments 参数是传递给函数的所有参数集合。无论是否有明确定义对应的形参,通过它我们都可以访问到函数的所有参数。

length 属性:

length - 实参的确切个数。可通过数组索引的方式来获取单个参数的值。

tips:

避免把arguments参数当作_数组_。你可能会被它的用法误导,毕竟它有length属性,而且可以通过数组下标的方式访问到每一个元素。但它并非JavaScript数组,如果你尝试在arguments对象上使用数组的方法(例如,上一章中用到的sort方法),会发现最终会报错。arguments对象仅是一个类数组的结构,在使用中要尤为注意。

使用arguments参数对所有函数参数执行操作:

function test() {
    let sum = 0
    for (var i = 0; i < arguments.length; i ++) {
        sum += arguments[i]
    }
    return sum
}
let r = test(1, 2, 3, 4, 5)
console.log(r)

这个例子中我们首先定义了一个没有显式声明任何参数的sum函数,尽管如此,我们依然可以通过arguments对象访问所有的函数参数。遍历所有的参数即可计算它们的和。

arguments对象作为函数参数的别名:

arguments参数有一个有趣的特性:它可以作为函数参数的别名。例如,如果为arguments[0]赋一个新值,那么,同时也会改变第一个参数的值。

function test() {
    arguments[0] = 20
    console.log(arguments)
}
test(1, 2)

注意:

将arguments对象作为函数参数的别名使用时会影响代码的可读性,因此在JavaScript提供的严格模式(strict mode)中将无法再使用它。
 

this参数:函数上下文

当调用函数时,除了显式提供的参数外,this参数也会默认地传递给函数。this参数是面向对象JavaScript编程的一个重要组成部分,代表函数调用相关联的对象。因此,通常称之为函数上下文。
函数上下文

是来自面向对象语言(如Java)的一个概念。在这些语言中,this通常指向定义当前方法的类的实例

this参数的指向:
this参数的指向不仅是由定义函数的方式和位置决定的,同时还严重受到函数调用方式的影响。

函数的调用方式对函数内代码的执行有很大的影响,主要体现在this参数以及函数上下是如何创建的。这点尤为重要。

调用方式:

(1)作为函数了,直接被调用 function test () { }   ->   test()

(2)作为一个方法,关联在一个对象上,实现面向对象编程。obj = { test: () => {} } ->   obj.test
(3)作为一个构造函数 (constructor)——new Test()  实例化一个新的对象

(4)通过函数的 apply 或者 call 方法——  test.apply(ninja)  或者  test.call(ninja)

1、函数直接被调用:

如果一个函数没有作为方法、构造函数或者通过apply和call调用的话,我们就称之为作为函数被直接调用。

当以下边三种方式调用时,函数上下文(this关键字的值)有两种可能性:在非严格模式下,它将是全局上下文(window对象),而在严格模式下,它将是 undefined

function test () {}
test() // 函数定义作为函数被调用

var test = function () {}
test() // 函数表达式作为函数被调用

(function () {})() // 会被立即调用的函数表达式

2、函数作为方法被调用:

当函数作为某个对象的方法被调用时,该对象会成为函数的上下文,并且在函数内部可以通过this访问到。这也是JavaScript实现面向对象编程的主要方式之一。

let obj = {
    test: function() {}
}
obj.test()

3、函数作为构造函数调用:

函数作为构造函数调用并没有什么特别之处。构造函数的声明和其他函数类似,通过可以使用函数声明和函数表达式很容易地构造新的对象。

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

1、创建一个新的空对象。

2、该对象,作为this参数传递给构造函数,从而成为构造函数的函数上下文。
3、新构造的对象作为new 运算符的返回值返回。

下边图中:

当使用关键字new调用函数时,会创建一个空的对象实例并将其设置为构造函数的上下文(this参数)
 

注意:

1、构造函数的目的是根据初始条件对函数调用创建的新对象进行初始化。

4、使用call和apply方法调用:

试想下,如果我们想改变函数上下文怎么办?如果想要显式指定它怎么办?如果……好吧,我们为什么会提出这样的问题?

JavaScript为我们提供了一种调用函数的方式,从而可以显式的指定任何对象作为函数的上下文。我们可以使用每个函数上都存在的这两种方法来完成:apply call

是的,我们所指的正是函数的方法。作为第一类对象(顺便说一下,函数是由内置的Function构造函数所创建),函数可以像其他对象类型一样拥有属性,也包括方法。

若想使用apply方法调用函数,需要为其传递两个参数:

作为函数上下文的对象和一个数组作为函数调用的参数。call方法的使用方式类似,不同点在于是直接以参数列表的形式,而不再是作为数组传递。


方法的第一个参数都会被作为函数上下文,不同处在于后续的参数。apply方法只需要一个额外的参数,也就是一个包含参数值的数组;call方法则需要传入任意数量的参数值,这些参数将用作函数的实参。

call和apply这两个方法对于我们要特殊指定一个函数的上下文对象时特别有用,在执行回调函数时可能会经常用到。
 

总结:

1、

当调用函数时,除了传入在函数定义中显式声明的参数之外,同时还传入两个隐式参数:arguments与this。arguments参数是传入函数的所有参数的集合。具有length属性,表示传入参数的个数,通过arguments参数还可获取那些与函数形参不匹配的参数。在非严格模式下,arguments对象是函数参数的别名,修改arguments对象会修改函数实参,可以通过严格模式避免修改函数实参。

函数的调用方式有4种:

(1)作为函数调用:skulk();

(2)作为方法调用:ninja.skulk();

(3)作为构造函数调用:new Ninja();

(4)通过apply与call方法调用:skulk.apply(ninja)或skulk.call(ninja)。

函数的调用方式影响this的取值。

如果作为函数调用,

(1)在非严格模式下,this指向全局window对象;

         在严格模式下,this指向undefined。

作为方法调用,

this通常指向调用的对象。

作为构造函数调用,

this指向新创建的对象。

(5)通过call或apply调用,this指向call或apply的第一个参数。

箭头函数没有单独的this值,this在箭头函数创建时确定。所有函数均可使用bind方法,创建新函数,并绑定到bind方法传入的参数上。被绑定的函数与原始函数具有一致的行为。

猜你喜欢

转载自blog.csdn.net/qq_42778001/article/details/106915684