前端学习笔记

标准库 Function

2019-08-03  本文已影响2人  _ClariS_

函数的本质

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

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

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)
}

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

上一篇下一篇

猜你喜欢

热点阅读