zoukankan      html  css  js  c++  java
  • javascript函数篇一、理解javascript中的函数参数(arguments对象相关问题)和函数名

    本文内容:

    • 理解函数是对象,函数名是指针;
    • 理解函数的参数问题 ===> arguments对象相关

    今天看了javascript函数的相关知识,果然平时用多了各种框架,对于原生js的掌握并没那么深入,每次看都有新的收获,本篇文章和大家分享对于函数名和函数参数的理解,以及为什么JS中没有函数重载的概念。

    函数名是指向函数对象的指针
    首先要知道Javascript中的函数实际上也是对象,每个函数都是Function类型的实例而已。因为是对象,所以函数名其实和包含对象指针的其他变量没有什么区别,也是一个指向函数对象的指针。

    var obj = {}
    function a () {
    console.log(1)
    }

    如上,变量obj其实是指向一个空对象的指针,同样函数名a与变量obj并没什么不同,也是指向此函数对象的一个指针。
    **再次强调一遍,函数名仅仅是指向函数对象的指针!**
    那么下面的例子就可以很好的理解了:

    function a (num1, num2) {
        return num1 + num2
    }
    var b = a
    alert(b(1,1)) // 2
    a = null
    alert(b(1,1)) // 2

    以上代码中,首先定义了一个函数a,然后将其赋值给变量b, 因为知道了a是指向我们所定义的函数的指针,所以这个赋值操作其实做的是将a指向的地址传递给变量b,此时b也指向了我们定义的函数对象,那么调用b就会执行我们定义的函数,即便接下来改变了a的指向为一个空对象,但并不影响b的指向,也就依然能正常执行函数,输出函数结果2.过程如下:

    理解函数参数
    javascript中的函数参数与其他语言中的函数参数有所不同,javascript中的参数没有参数个数和类型的限制,也就是说,无论你定义的时候定义了几个参数,实际调用的时候依然可以传任意多个参数,甚至不传,更没有参数类型的限制。
    之所以是这样,原因是javascript中的在内部使用一个数组来表示的。函数内部接收到的始终是这个数组,不关心数组有哪些参数或者是否有参数。而在函数体内可以通过arguments来访问这个参数数组,获取到函数的每一个参数。
    arguments
    只是一个类似数组的对象,但它并不是Array的实例。它同样可以通过下面这种方式访问它的每一个元素:arguments[0],arguments[1]...同样拥有length属性,表示函数传递进来的参数个数。

    function doSomething (num1, num2) {
        if (arguments.length > 2) { // 如果函数有两个以上的参数
            console.log(arguments[2]) // 输出第三个参数
        }
    }    

    arguments获取到的函数参数与对应的函数形参的同步特性
    arguments有一个特殊的性质,就是它的值永远和对应的形参保持同步。
    举个例子就明白了,如果一个函数的参数有三个,实际调用的时候只传了两个参数,那么前两个arguments元素与形参保持同步,即共享数据并且改变时保持同步,而第三个形参与arguments[2]是不同步的。

    function fn (a, b, c) {
        console.log(a === arguments[0]) // true
        a = {name: 'zhangsan', age: 18}
        console.log(arguments[0]) // {name: 'zhangsan', age: 18}
        console.log(b === arguments[1]) // true
        arguments[1] = {name: 'lisi'}
        console.log(b) // {name: 'lisi'}
        c = 40
        console.log(arguments[2]) // undefined
        arguments[2] = '123'
        console.log(c) // 40, 可见c与arguments[2]是互不影响的
    }
    var p1 = {name: 'xiaoming', age: 6}
    var p2 = {age: 10}
    fn(p1, p2)

    **注意:没被传递参数的形参和相应的arguments元素都被赋值为undefined,就像是定义了变量,但没有被初始化一样。**
    *另外,形参与对应的arguments元素保持同步,并不代表他们是读取相同的内存空间,它们的内存空间是独立的,只是值会同步而已。*

     arguments对象三个有用属性:length、callee、properties-indexes

    1. length:真正传递的参数个数;
    2. callee:指向当前函数的引用(caller:调用当前函数的函数,两者不同以后会有介绍);
    3. properties-indexes:函数的参数值(按参数列表从左到右排列)

    arguments.callee应用如下:

    function fn(n) {
        if (n <= 1) {
            return 1
        } else {
            return n * arguments.callee(n - 1) // arguments.callee指向当前函数的引用,这里相当于是在递归调用fn()
        }
    }
    console.log(5) // 20        

    虽然使用arguments.callee消除了函数的执行与函数名的紧密耦合,不论函数名怎么改变,这里都能正确递归调用此函数。但是访问arguments是一个非常昂贵的操作,因为arguments是一个很大的对象,每次递归时都需要重新创建。影响现代浏览器的性能,还会影响闭包,所以arguments.callee并不赞成使用。

     将arguments对象转为数组
      有两种方法可以将arguments对象转为数组:

    1. Array.prototype.slice.apply(arguments);
    2. Array.from(arguments); 

    到这里对函数参数和函数名做了这些了解后,我们就可以深入理解下为什么javascript中没有函数重载了。请看下篇文章:
    [深入理解为什么javascript没有函数重载](https://www.cnblogs.com/youyang-2018/p/11706062.html)

  • 相关阅读:
    LeetCode 189. Rotate Array
    LeetCode 965. Univalued Binary Tree
    LeetCode 111. Minimum Depth of Binary Tree
    LeetCode 104. Maximum Depth of Binary Tree
    Windows下MySQL的安装与配置
    LeetCode 58. Length of Last Word
    LeetCode 41. First Missing Positive
    LeetCode 283. Move Zeroes
    《蚂蚁金服11.11:支付宝和蚂蚁花呗的技术架构及实践》读后感
    删除docker下的镜像
  • 原文地址:https://www.cnblogs.com/youyang-2018/p/11706056.html
Copyright © 2011-2022 走看看