zoukankan      html  css  js  c++  java
  • JS 函数 学习笔记

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

    声明函数的 5 种方式

    • 具名函数 (function 命令)

       function f(x, y){
           return x + y;
       }
       f.name // 'f'
      
    • 函数表达式

      var f
      f = function(x, y){
      	return x + y;
      }
      f.name // 'f'
      
    • 具名函数赋值

      var f
      f = function f2(x, y){
          return x + y;
      }
      f.name // 'f2'
      console.log(f2) // undefined
      
    • window.Function

      var f = new Function('x', 'y', 'return x + y;')
      f.name // 'anonymous'
      
    • 箭头函数

      var f = (x, y) => {
          return x + y;
      }
      var sum = (x, y) => x + y
      var n2 = n => n*n
      

    函数的特性

    • 如果同一个函数被多次声明,后面的声明就会覆盖前面的声明

    • 函数内部的return语句表示返回,JavaScript 引擎遇到return语句,就直接返回return后面的哪个表达式的值,即时后面还有语句也不会得到执行。return语句不是必须的,如果没有,函数默认返回undefined

    • 在 JavaScript 中函数可以看成一个种值,与其他值(数字,字符串,布尔值等)地位相同,称为第一等公民,函数可以当作惭怍传递给另外一个函数。

    • 函数名的提升

      JavaScript 引擎将函数名视同变量名,所以采用function命令声明函数时,整个函数会像变量声明一样,被提升到代码头部,所以,下面的代码不会出错。

      f();
      
      function f() {}
      // 表面上,代码好像在声明之前就调用了函数f。
      // 但是实际上,由于“变量提升”,函数 f 被提升到了代码头部,也就是在调用之前已经声明了
      

      如果使用函数表达式的方式,声明前就调用,下面的代码就会出错

      f();
      var f = function (){}
      // TypeError: f is not a function
      
      // 等价于
      var f;
      f();
      f = function(){}
      

    函数作用域

    作用域(scope)指的是变量存在的范围,在 ES5 的规范中只有全局作用域和函数作用域,ES6 新增了块级作用域。

    全局作用域:变量在整个程序中一直存在,所有地方都可以读取

    函数作用域:变量只在函数内部存在,外部无法访问函数内部的变量,除了使用闭包。

    • 函数内部可以读取全局变量

      var v = 1;
      
      function f() {
        console.log(v);
      }
      
      f()
      // 1
      
    • 在函数内部定义的变量,外部无法读取,称为“局部变量”

      function f(){
        var v = 1;
      }
      
      v // ReferenceError: v is not defined
      
    • 函数内部定义的变量,会在该作用域内覆盖同名全局变量,就近原则

      var v = 1;
      
      function f(){
        var v = 2;
        console.log(v);
      }
      
      f() // 2
      v // 1
      
    • 与全局作用域一样,函数作用域内部也会产生“变量提升”现象。var命令声明的变量,不管在什么位置,变量声明都会被提升到函数体的头部

      function foo(x) {
        if (x > 100) {
          var tmp = x - 100;
        }
      }
      
      // 等同于
      function foo(x) {
        var tmp;
        if (x > 100) {
          tmp = x - 100;
        };
      }
      
    • 函数本身也是一个值,也有自己的作用域。它的作用域与变量一样,就是其声明时所在的作用域,与其运行时所在的作用域无关。参考本文中的 题目二

    闭包

    function f1() {
      var n = 999;
      function f2() {
        console.log(n);
      }
      return f2;
    }
    
    var result = f1();
    result(); // 999
    

    函数 f2 和变量 n 的组合就形成了一个闭包。

    「函数」和「函数内部能访问到的变量」(也叫环境)的总和,就是一个闭包

    闭包的作用:

    闭包常常用来「间接访问一个变量」。换句话说,「隐藏一个变量」,让函数执行形成的私有作用域,保护里面的变量不受外界干扰的机制。

    var api = (function() {
      var lives = 50
      var 奖励一条命 = function() {
        lives += 1
        console.log('当前剩余' + lives)
      }
      var 死一条命 = function() {
        lives -= 1
        console.log('当前剩余' + lives)
      }
      return {
        a: 奖励一条命,
        b: 死一条命
      }
     
    }())
    api.a() // 当前剩余51
    api.b() // 当前剩余50
    api.b() // 当前剩余49
    

    参考阅读 JS 中的闭包是什么

    立即执行函数

    (function(){ 
    /* code */ 
    }());
    
    // 或者
    
    (function(){ 
    /* code */ 
    })();
    

    通常情况下,只对匿名函数使用这种“立即执行的函数表达式”。

    它的目的有两个:

    一是不必为函数命名,避免了污染全局变量;

    二是 IIFE 内部形成了一个单独的作用域,可以封装一些外部无法读取的私有变量。

    练习题

    题目一

    var a = 1
    function f1(){
        alert(a) // 是多少
        var a = 2
    }
    f1.call()
    
    // 遇到代码题,请先提升声明!
    // 遇到代码题,请先提升声明!
    // 遇到代码题,请先提升声明!
    
    var a = 1
    function f1(){
        var a
        alert(a)
        a = 2
    }
    f1.call() 
    // 答案: alert 一个 undefined
    

    题目二

    var a = 1
    function f1(){
        var a = 2
        f2.call()
    }
    function f2(){
        console.log(a) // 是多少
    }
    f1.call()
    // 函数本身也是一个值,也有自己的作用域。
    // 它的作用域与变量一样,就是其声明时所在的作用域,与其运行时所在的作用域无关。
    
    // 答案:输出 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?
        }
    }
    
    // 答案 6
    
    // 如何解决?
    // 1. 使用 let 声明变量 i
    // 2. 使用立即执行函数
    
    var liTags = document.querySelectorAll('li')
    for (var i = 0; i < liTags.length; i++) {
      (function(item) {
        liTags[item].onclick = function() {
          console.log(item)
        }
      })(i);
    
    }
    
  • 相关阅读:
    POJ 1185 炮兵阵地 经典的 状态压缩dp
    hdu 1565 方格取数(1) 状态压缩dp
    poj Corn Fields 状态压缩dp。
    fzu 2138 久违的月赛之一 容斥。
    fzu 2136 取糖果 好几种方法解决。
    hdu 1231 最大连续子序列
    选择排序
    SharedPrefernces使用实例讲解
    SharedPrefernces使用实例讲解
    可以ping通,但是不能connect
  • 原文地址:https://www.cnblogs.com/wubh/p/JavaScript-Function.html
Copyright © 2011-2022 走看看