zoukankan      html  css  js  c++  java
  • Javascript_函数

    JavaScript 三种声明函数的方法
    
    1. function 命令 
    function print(s) {
        console.log(s);
    }
    
    2. 函数表达式,这种写法将一个匿名函数赋值给变量。
    
    var print = function(s) {
        console.log(s);
    }
    
    3. Function 构造函数,几乎无人使用
    
    var add = new Function(
        'x',
        'y',
        'return x + y'
    
    );
    
    圆括号运算符,return 语句和递归
    function fib(num) {
      if (num === 0) return 0;
      if (num === 1) return 1;
      return fib(num - 2) + fib(num - 1);
    }
    
    第一等公民
    function add(x, y) {
      return x + y;
    }
    
    // 将函数赋值给一个变量
    var operator = add;
    
    // 将函数作为参数和返回值
    function a(op){
      return op;
    }
    a(add)(1, 1)
    // 2
    
    
    
    函数名的提升
    JavaScript 引擎将函数名视同变量名,所以采用function命令声明函数时,整个函数会像变量声明一样,被提升到代码头部。
    
    函数的属性和方法
    
     function fib(num) {
      if (num === 0) return 0;
      if (num === 1) return 1;
      return fib(num - 2) + fib(num - 1);
    }
    undefined
    fib.name
    //"fib"
    fib.length
    //1
    
    
    
    
    
    函数作用域
    
    var v = 1; //全局变量
    //
    function f() {
        var v = 2; //局部变量,函数内部变量会覆盖全局变量
    }
    
    //注意,对于var命令来说,局部变量只能在函数内部声明,在其他区块中声明,一律都是全局变量。
    
    if (true) {
        var x = 5;  // 这里的 x 是全局变量,因为它不在函数中
        
    }
    
    
    函数内部的变量提升
    
    //与全局作用域一样,函数作用域内部也会产生“变量提升”现象。var命令声明的变量,不管在什么位置,变量声明都会被提升到函数体的头部。
    function foo(x) {
      if (x > 100) {
        var tmp = x - 100;
      }
    }
    
    // 等同于
    function foo(x) {
      var tmp;
      if (x > 100) {
        tmp = x - 100;
      };
    }
    
    函数本身的作用域
    //函数本身也是一个值,也有自己的作用域。它的作用域与变量一样,就是其声明时所在的作用域,与其运行时所在的作用域无关。
    var a = 1;
    var x = function () {
      console.log(a);
    };
    
    function f() {
      var a = 2;
      x();   //函数x是在函数f的外部声明的,所以它的作用域绑定外层,内部变量a不会到函数f体内取值,所以输出1,而不是2。
    }
    
    f() // 1
    
    
    function foo() {
      var x = 1;
      function bar() {
        console.log(x);
      }
      return bar;    
    }
    
    var x = 2;
    var f = foo();
    f() // 1
    
    
    参数
    //函数参数如果是原始类型的值(数值、字符串、布尔值),传递方式是传值传递(passes by value)。这意味着,在函数体内修改参数值,不会影响到函数外部。
    var p = 2;
    
    function f(p) {
      p = 3;
    }
    f(p);
    
    p // 2
    //但是,如果函数参数是复合类型的值(数组、对象、其他函数),传递方式是传址传递(pass by reference)。也就是说,传入函数的原始值的地址,因此在函数内部修改参数,将会影响到原始值。
    
    
    var obj = { p: 1 };
    
    function f(o) {
      o.p = 2;
    }
    f(obj);
    
    obj.p // 2
    
    //注意,如果函数内部修改的,不是参数对象的某个属性,而是替换掉整个参数,这时不会影响到原始值。
    
    var obj = [1, 2, 3];
    
    function f(o) {
      o = [2, 3, 4];
    }
    f(obj);
    
    obj // [1, 2, 3]
    
    同名参数
    
    
    如果有同名的参数,则取最后出现的那个值。
    
    function f(a, a) {
      console.log(a);
    }
    
    f(1, 2) // 2
    
    //调用函数f()的时候,没有提供第二个参数,a的取值就变成了undefined。这时,如果要获得第一个a的值,可以使用arguments对象。
    function f(a, a) {
      console.log(a);
    }
    
    f(1) // undefined
    
    function f(a, a) {
      console.log(arguments[0]);
    }
    
    f(1) // 1
    
    
    arguments 对象
    
    //由于 JavaScript 允许函数有不定数目的参数,所以需要一种机制,可以在函数体内部读取所有参数。这就是arguments对象的由来。
    
    //arguments对象包含了函数运行时的所有参数,arguments[0]就是第一个参数,arguments[1]就是第二个参数,以此类推。这个对象只有在函数体内部,才可以使用。
    
    
    var f = function (one) {
      console.log(arguments[0]);
      console.log(arguments[1]);
      console.log(arguments[2]);
    }
    
    f(1, 2, 3)
    // 1
    // 2
    // 3
    
    
    var f = function(a, b) {
      arguments[0] = 3;
      arguments[1] = 2;
      return a + b;
    }
    
    f(1, 1) // 5
    
    
    //上面代码中,函数f()调用时传入的参数,在函数内部被修改成3和2。
    
    //严格模式下,arguments对象与函数参数不具有联动关系。也就是说,修改arguments对象不会影响到实际的函数参数。
    
    
    
    var f = function(a, b) {
      'use strict'; // 开启严格模式
      arguments[0] = 3;
      arguments[1] = 2;
      return a + b;
    }
    
    f(1, 1) // 2
    
    上面代码中,函数体内是严格模式,这时修改arguments对象,不会影响到真实参数a和b。
    
    通过arguments对象的length属性,可以判断函数调用时到底带几个参数。
    
    
    function f() {
      return arguments.length;
    }
    
    f(1, 2, 3) // 3
    f(1) // 1
    f() // 0
    
    
    
    
    函数的其他知识点
    
    
    //闭包
    //闭包(closure)是 JavaScript 语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。
    
    //理解闭包,首先必须理解变量作用域。前面提到,JavaScript 有两种作用域:全局作用域和函数作用域。函数内部可以直接读取全局变量。
    
    function f1() {
      var n = 999;
      function f2() {
        console.log(n);
      }
      return f2;
    }
    
    var result = f1();
    result(); // 999
    
    //闭包就是函数f2,即能够读取其他函数内部变量的函数。由于在 JavaScript 语言中,只有函数内部的子函数才能读取内部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数”。闭包最大的特点,就是它可以“记住”诞生的环境,比如f2记住了它诞生的环境f1,所以从f2可以得到f1的内部变量。在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。
    //闭包的最大用处有两个,一个是可以读取外层函数内部的变量,另一个就是让这些变量始终保持在内存中,即闭包可以使得它诞生环境一直存在。请看下面的例子,闭包使得内部变量记住上一次调用时的运算结果。
    
    
    
    function createIncrementor(start) {
      return function () {
        return start++;
      };
    }
    
    var inc = createIncrementor(5);   // 将 createIncrementor 内部方法赋值给变量 inc 
    
    inc() // 5
    inc() // 6
    inc() // 7
    
    闭包的另一个用处,是封装对象的私有属性和私有方法
    function Person(name) {
      var _age;
      function setAge(n) {
        _age = n;
      }
      function getAge() {
        return _age;
      }
    
      return {    // return 通过 对象这个数据类型返回 函数内部的方法
        name: name,
        getAge: getAge,
        setAge: setAge
      };
    }
    
    var p1 = Person('张三');
    p1.setAge(25);
    p1.getAge() // 25
    
    
    立即调用的函数表达式(IIFE)
    
    var f = function f(){ return 1}();
    f // 1
    
    //函数定义后立即调用的解决方法,就是不要让function出现在行首,让引擎将其理解成一个表达式。最简单的处理,就是将其放在一个圆括号里面。
    
    (function(){ /* code */ }());
    // 或者
    (function(){ /* code */ })();
    
    
    
    
    eval 命令
    
    //eval命令接受一个字符串作为参数,并将这个字符串当作语句执行。
    
    eval('var a = 1;');
    a // 1
    
    
    //eval没有自己的作用域,都在当前作用域内执行,因此可能会修改当前作用域的变量的值,造成安全问题。
    
    var a = 1;
    eval('a = 2');
    
    a // 2
    
    (function f() {
      'use strict';
      eval('var foo = 123');
      console.log(foo);  // ReferenceError: foo is not defined
    })()
    
    
    eval 的别名调用,不推荐使用
  • 相关阅读:
    MongoDB的基本操作
    Python 进阶 之 协程
    sublime text3 3143 注册码
    git add 文档
    Corosync 配置描述
    Centos 7 设置 DNS
    2017百度春招<度度熊买帽子的问题>
    leetcode 160. Intersection of Two Linked Lists
    leetcode 155. Min Stack
    leetcode 141 142. Linked List Cycle
  • 原文地址:https://www.cnblogs.com/zy09/p/14340223.html
Copyright © 2011-2022 走看看