标签: 函数

  • 立即执行函数

    作用

    创造一个作用域空间,防止变量冲突或覆盖.

    • 立即执行
    • 只执行一次
    • 执行完毕,立即销毁

    两种写法

    (function (){}()) //W3C推荐写法
    
    (function (){})()
    

    为什么立即执行函数外面要加(),不加可不可以呢,我们来试一下

    function(){ 
       console.log('this is a function')
    }()
    //Uncaught SyntaxError: Function statements require a function name
    //报错,意思是函数声明需要一个函数名
    

    虽然匿名函数属于函数表达式,但未进行赋值,所以javascript解析时将开头的function当做函数声明,故报错提示需要函数名;

    立即执行函数里面的函数必须是函数表达式

    函数声明和函数表达式区别
    let func = function() {
        return 1;
    }();
    console.log(func) //1 
    

    为什么给一个匿名函数赋值就可以正常了呢?

    匿名函数前加了 “=” 有了运算符后,将函数声明转化为函数表达式。

    我们可以理解为在匿名函数前加了 “=” 有了运算符后,将函数声明转化为函数表达式。

    我们拿!,+,-,()…等运算符来进行测试:
    !function(){
        console.log('this is a function1')
    }()
    // this is a function1
        
    +function(){
        console.log('this is a function2')
    }()
    // this is a function2
        
    -function(){
        console.log('this is a function3')
    }()
    // this is a function3
        
    ;(function(){
        console.log('this is a function4')
    })()
    // this is a function4
    

    由此可见,加运算符确实可将函数声明转化为函数表达式

    需要注意的地方

    注意在代码console.log(‘this is a function4’)这个函数我在最前面加上了一个“;”(分号) 为什么要加这分号,不加行不行呢,大家可以验证一下。 不加会报错(Uncaught TypeError: (intermediate value)(…) is not a function)

    上面的代码有一些多,我们截取一部分来讲
    -function(){
        console.log('this is a function3')
    }()
    
    (function(){
        console.log('this is a function4')
    })()
    

    这段代码一样会报错,因为ECMAScript规范具有分号自动插入规则,但是在上面代码中,在第一个立即执行函数末尾却不会插入,因为第二个立即执行函数,会被解释为如下形式:

    -function(){
        console.log('this is a function3')
    }()(function(){console.log('this is a function4')})()
    

    因此我们在最后一个立即执行函数前面加一个分号;(是为了防止前一个立即函数尾部没有的分号;) 其实还有其它的方式也可以实现,使用void 运算符,个人感觉这种方式更优雅

    -function(){
        console.log('this is a function3')
    }()
    
    void (function(){
        console.log('this is a function4')
    })()
    

    立即执行函数的应用场景

    1、代码在页面加载完成之后,不得不执行一些设置工作,比如时间处理器,创建对象等等.

    2、所有的这些动作只需要执行一次,比如只需要显示一个事件.

    3、将代码包裹在它的局部作用域中,不会让任何变量泄漏成全局变量.

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/xu_song/article/details/107077675

  • 函数声明、函数表达式、匿名函数

    函数声明

    function func() { console.log('this is a function') };
    

    首先使用 function 关键字声明一个函数,再执行一个函数名,叫函数声明。

    函数表达式

    let func = function() { console.log('this is a function') };
    

    使用 function 关键字声明一个函数,但未给函数命名,将匿名函数赋予一个变量,叫函数表达式,这是最常见的函数表达式语法形式。

    匿名函数

    function() { console.log('this is a function') };
    

    使用 function 关键字声明一个函数,但未给函数命名,所以叫匿名函数,匿名函数属于函数表达式,匿名函数有很多作用,赋予一个变量则创建函数,赋予一个事件则成为事件处理程序或创建闭包等等。

    函数声明和函数表达式区别

    1、JavaScript 引擎在解析 JavaScript 代码时会“函数声明提升”当前执行环境(作用域)上的函数声明,而函数表达式必须等到 JavaScript 引擎执行到它所在行时,才会从上而下一行一行地解析函数表达式。

    2、函数表达式后面可以加括号立即调用该函数,函数声明不可以,只能以 func() 形式调用。

    我们看一下下面的例子就会明白

    函数声明

    func(); //正常输出this is a function
    function func() {
        console.log('this is a function') 
    }; 
    

    函数表达式

    func();// Uncaught SyntaxError: Invalid or unexpected token
    //函数表达式报错,func未保存对函数的引用,函数调用需放在函数表达式后面
    var func = function() { 
        console.log('this is a function') 
    };
    

    版权声明:本文为CSDN博主「xu_song」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/xu_song/article/details/107077675

  • 高阶函数

    高阶函数可以被简单理解为函数的高级应用,JavaScript函数可以被当来对待,基于这个特性实现函数的高级应用。

    是 JavaScript 中的数据,如数值字符串布尔对象等。

    函数表达式

    • 函数也是数据
    • 把函数赋值给变量
    let abc = function(){}
    
    • 普通函数的声明与调用无顺序限制,推荐做法先声明再调用
    • 函数表达式必须要先声明再调用

    回调函数

    如果将函数 A 做为参数传递给函数 B 时,我们称函数 A 为回调函数 简单理解: 当一个函数当做参数来传递给另外一个函数的时候,这个函数就是回调函数

    常见的使用场景

    //1.间歇函数
    function fn(){
    		console.log('我是谁')
    }
    //fn传递给了setIterval,fn就是回掉函数
    setInterval(fn,1000)
    
    //2.事件监听
    //这里匿名函数为回掉函数
    box.addEventListener('click',function(){
      console.log('123')
    })
    
    • 把函数当做另外一个函数的参数传递,这个函数就叫回调函数
    • 回调函数本质还是函数,只不过把它当成参数使用
    • 使用匿名函数做为回调函数比较常见
  • 函数

    使用

    function 函数名(){
    		函数体
    }
    

    命名规范

    • 和变量命名基本一致
    • 尽量小驼峰式命名法
    • 前缀应该为动词
    • 命名建议:常用动词约定 can has is get set load

    调用

    函数名()
    

    注意:声明(定义)的函数必须调用才会真正被执行,使用 () 调用函数

    传参

    • 调用函数时,需要传入几个数据就写几个,用逗号隔开
    • 开发中尽量保持形参和实参个数一致
    function 函数名(形参1,形参2,....){
      	函数体
    }
    函数名(实参1,实参2,....)
    

    形参如果不被赋值,就是undefined

    小技巧

    1.利用逻辑中断

    function getSum(x,y){
      x = x || 0
      y = y || 0
      console.log(x + y)
    }
    getSum(1,2)  // 3
    getSum()     // 0
    

    2.直接赋值

    //没有参数x = 0 , y = 0  如果有参数传来,则用实参赋值
    function getSum(x = 0,y = 0){ 
      x = x || 0
      y = y || 0
      console.log(x + y)
    }
    getSum(1,2)  // 3
    getSum()     // 0
    
    实参少于/多于形参
    function fn(x, y) {
        console.log(x + y)
    }
    
    // 1. 实参个数少于形参   返回的结果 NaN
    fn(1)   // x = 1 y = underfined
    
    // 2. 实参个数大于形参 非诚勿扰
    fn(1, 2, 3)   // x = 1 , y = 2  3没人接
    
    小知识(了解)

    函数内部可以使用arguments得到一个伪数组

      // arguments 函数内有效 表现形式:伪数组
      // 伪数组 比真数组 少了一些 pop()  push()  等方法
    function fn() {
      console.log(arguments) //  [1,2,3]
      let sum = 0
      for (let i = 0; i < arguments.length; i++) {
        sum += arguments[i]
      }
      console.log(sum)
    }
    
    fn(1, 2, 3)
    

    返回值

    语法:return 数据

    • return后面的代码均不会被执行!
    • return会立即结束当前函数
    • 函数可以没有 return,这种情况函数默认返回值为 undefined

    作用域

    1. 全局作用域(全局有效)

    作用于所有代码执行的 环境(整个script标签内部)或者一个独立的js文件

    1. 局部作用域(局部有效)

    作用于函数内的代码环境,就是局部作用域

    因为跟函数有关系,所以也称为函数作用域

    1. 块级作用域({} 内有效)

    块作用域由{ }包括,if语句和for语句里面的{ }

    变量的作用域

        <script>
    //————————————————————————————————————
          let a = 0         //全局作用域 
    //————————————————————————————————————
          function fn() {
            let b = 0       //局部作用域
          }
          fn()
    //————————————————————————————————————
          if (true) {
            let c = 0      //块级作用域
          }
    //————————————————————————————————————
        </script>
    
    变量类型
    全局变量(函数外部let 的变量) 全局变量在任何区域都可以访问和修改
    局部变量(函数内部let的变量) 局部变量只能在当前函数内部访问和修改
    块级变量({} 内部的let变量) let定义的变量,只能在块作用域里访问,不能跨块访问,也不能跨函数访问

    特殊情况:

    • 如果函数内部或者块级作用域内部(if、for···),变量没有声明,直接赋值,也当全局变量看(强烈不推荐)
    • 函数内部的形参可以看做是局部变量

    作用域链

    采取就近原则的方式来查找变量最终的值

    <script>
      function f1() {
        let num = 123
        function f2() {  
          let num = 0
          console.log(num)
        }
        f2()
      }
      let num = 456
      f1()
    </script>
    

    匿名函数

    //——————具名函数——————
    
    声明 function 函数名(){}
    调用 函数名()
    
    //——————匿名函数——————
    
    声明 let 变量名 = function(){}
    调用 变量名()
    传参 变量名(参数)
    
    //———————————————————
    
    //例1
    let btn = document.querySelector('button')
    btn.onclick = function(){
      alert('123')
    }
    
    //例2
    let btn = document.querySelector('button')
    btn.addEventListener('click',function(){
        alert('123')
    })
    

    立即执行函数

    防止变量污染

    场景:避免全局变量之间的污染

    立即执行无需调用

    //写法1
    (  function(){}  )()
    
    //写法2
    (  function(){} () )
    

    注意:多个立即执行函数要用 ; 隔开,要不然会报错