标准库 Function

作者: _ClariS_ | 来源:发表于2019-08-03 13:50 被阅读2次

    函数的本质

    函数是一段可以反复调用的代码块。函数还能接受输入的参数,不同的参数会返回不同的值。

    函数本质上就是一个可以执行代码的对象

    f 表示这个对象,f.call() 表示执行这个对象的函数体(f.functionBody)

    函数的 5 种声明方式

    1. 具名函数
     function f(x,y){
         return x+y
     }
     f.name // 'f'
    
    1. 匿名函数
     var f
     f = function(x,y){
         return x+y
     }
     f.name // 'f'
    
    1. 具名函数赋值
     var f1
     f1 = function f2(x,y){ 
          return x+y
     }
     f1.name // 'f2'
     f2.name // 报错 f2 is not defined
     console.log(f2) // 报错 f2 is not defined
    

    问:为什么console.log(f2)会报错?

    答:见下图(不一致性是 JS 的一个垃圾之处)

    1. window.Function(函数对象)
     var f = new Function('x','y','return x+y')
     f.name // "anonymous"
    
    1. 箭头函数
     var f = (x,y) => {
         return x+y
     }
     var sum = (x,y) => x+y // 右边只有一个表达式,可以不写括号和 return
     var n2 = n => n*n // 左边参数只有一个,可以不加括号
    

    注意:
    console.log()也是一个函数,它的返回值是 undefined,它返回什么跟它打印什么一点关系都没有

    例如,var a = console.log(1),问 a 的值是多少?

    虽然console.log(1)打印出1,但它返回的是undefined,因此 a 的值为 undefined

    如何调用函数

    f.call(asThis, input1,input2)
    其中 asThis 会被当做 this,[input1,input2] 会被当做 arguments

    this 和 arguments
    function f(){
        'use strict'
        console.log(this)
        console.log(arguments)
        return undefined
    }
    f.call(1,2,3) // this 为 1,arguments 为 [2,3]
    
    1. call 的第一个参数可以用 this 得到

    普通模式下,如果 this 为 undefined 或空,浏览器会自动把 this 变成 window 对象

    普通模式

    严格模式(use strict)下,才会打印出 this 原本的值,如果 this 为 undefined,此时 this 的值才真正的是 undefined

    use strict
    1. call 后面的参数可以用 arguments 得到

    call stack(调用堆栈)

    原则:stack 总是先进后出

    查看几种常见的函数调用过程:

    stack overflow(堆栈溢出)

    如果堆栈占用的空间超过分配给它的空间,则会导致“堆栈溢出”错误。

    作用域(scope)

    • 按照语法树一层一层往上找声明,遵循就近原则
    作用域树

    问:如果在声明函数的时候没有加 var,就一定是在声明全局变量吗?
    答:很多人都会这么认为,但这种说法其实是错误的。
    例如 a = 3 ,会优先认为它是一个赋值,此时并没有声明;
    然后它会寻找自己当前所在的作用域内是否存在 a 的声明,若不存在声明,则会沿着作用域树一层一层地向上寻找声明;
    当在全局范围找到 a 的声明时,就将 a = 3 的值赋给全局变量 a;
    那么,a = 3 在什么情况下是在声明一个全局变量呢?
    在整个作用域树中都找不到对 a 的声明(包括全局范围),此时的 a = 3 就是在声明一个全局变量并给它赋值

    • 我们只能确定变量是哪个变量,但是不能确定变量的值
      例如
    var a = 1
    function f(){
       console.log(a) // 1
    }
    f.call()
    
    var a = 1
    function f(){
       console.log(a) // 2
    }
    a = 2
    f.call()
    

    上面两段代码中console.log(a)中的 a 是同一个 a (都为全局范围中的 a),但最终打印出的结果却不同。因为第二段代码中 a = 2 覆盖了之前的 a = 1,console.log(a)会最后打印出 2。

    由此可以看出,即便是确定的同一个变量,最后的值可能也是会发生变化的

    以下是几个面试题~~

    拿到代码直接做——必然会错。请先提升声明

    题目一:

    var a = 1
    function f1(){
        alert(a) // 是多少
        var a = 2
    }
    f1.call()
    

    提升声明后

    var a
    a = 1
    function f1(){
        var a
        alert(a) // 弹框弹出并提示 undefined
        a = 2
    }
    f1.call()
    

    题目二:

    var a = 1
    function f1(){
        var a = 2
        f2.call()
    }
    function f2(){
        console.log(a) // 是多少
    }
    f1.call()
    

    变量提升后

    var a
    a = 1
    function f1(){
    // f1 的作用域
        var a
        a = 2
        f2.call()
    }
    function f2(){
    // f2 的作用域
        console.log(a) // f2 的作用域中不存在对 a 的声明,此时应为全局范围中的 a ,因此打印出值 1 
    }
    f1.call()
    

    题目三:

    var a = 1
    function f1(){
        f2.call()
        console.log(a) // 是多少
        var a = 2
       function f2(){
           var a = 3
           console.log(a) // 是多少
       }
    }
    f1.call()
    console.log(a) // 是多少
    

    变量提升后

    var a
    a = 1
    function f1(){
        var a
       function f2(){
            var a
            a = 3
            console.log(a) // 3
       }
        f2.call()
        console.log(a) // undefined
        a = 2
    }
    f1.call()
    console.log(a) // 1
    

    题目四:

    var liTags = document.querySelectorAll('li')
    for(var i = 0; i<liTags.length; i++){
        liTags[i].onclick = function(){
            console.log(i) // 点击第 3 个 li 时,打印 2 还是打印 6?
        }
    }  // 点击第 3 个 li 时,i 取值为 2,但 i 遍历完成后变为 6,console.log(i) 会最后打印,因此会打印出 6
    

    闭包

    如果一个函数使用了它范围外的变量,那么(这个函数 + 这个变量)就叫做闭包

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

    这里只简单对闭包的概念做一下简单说明,如想更详细地了解,请阅读文章 闭包

    相关文章

      网友评论

        本文标题:标准库 Function

        本文链接:https://www.haomeiwen.com/subject/kiokdctx.html