您的位置:首页 > Web前端 > JavaScript

JS函数易错点及难点学习记录

2020-06-05 05:31 70 查看

文章目录

  • 3. 参数
  • 4. 函数提升
  • 5. 立即调用函数表达式(IIFE)
  • 6. eval命令
  • 1. 作用域

    作用域: function声明时的作用域,所以函数参数的取值范围为函数本身所在的作用域

    var a = 1;
    var x = function () {
    console.log(a);
    };
    
    function f() {
    var a = 2;
    x();
    }
    
    f() // 1

    2. 闭包

    2.1 概念理解

    衍生概念: 闭包 >> 定义在一个函数内部的函数:

    1. 当函数外部想要调用函数(f1)内部的局部变量,可以在函数内部定义一个子函数(f2),子函数可以使用父函数的局部变量,如果将子函数返回,就可以在外部使用局部变量 --链式作用域结构
    2. f2即为闭包
    function f1() {
    var n = 999;
    function f2() {
    console.log(n);
    }
    return f2;
    }
    
    var result = f1();
    result(); // 999

    2.2 状态保留

    外部调用局部变量依赖于闭包,也就是闭包的诞生环境(函数),所以,外部调用结束之前函数会一直存在于内存里
    函数调用的过程中,局部变量一直存在,且保留

    function increment(start) {
    //start局部变量
    return function () {
    return start++;// start += 1局部变量改变
    };
    }
    
    var inc = increment(5);
    
    inc() // 5
    inc() // 6
    inc() // 7

    2.3 封装对象的私有属性和方法

    function Person(name) {
    var _age;
    function setAge(n) {
    _age = n;
    }
    function getAge() {
    return _age;
    }
    
    return {
    name: name,
    getAge: getAge,
    setAge: setAge
    };
    }
    
    var p1 = Person('张三');
    p1.setAge(25);
    p1.getAge() // 25

    2.4 缺点

    外层函数的每次运行都会产生一个新的闭包,并且闭包中保存外层函数的内部变量,根据上文中提到的状态保留,内存消耗大,影响网页性能

    3. 参数

    多个参数: 传的参数少于参数列表个数时,忽略后面的参数;同名参数,取后者

    function f(a, a) {
    console.log(a);
    }
    
    f(1) // undefined
    //同名参数取后者,因为只有一个参数,第二个参数被忽略,所以undefined

    4. 函数提升

    JS将函数名视为变量名function f(){}会被函数提升

    var f = function () {
    console.log('1');
    }
    
    function f() {
    console.log('2');
    }
    
    f() // 1 ;后者函数提升,后声明函数覆盖先声明的同名函数,所以结果为1

    赋值逻辑不会被提升

    console.log(a);
    console.log(b);
    var a;
    var b = 1;
    undefined // a被变量提升
    undefined // b被变量提升,但是赋值不会被提升
    
    f();
    var f = function (){};
    // TypeError: undefined is not a function;赋值不被提升

    5. 立即调用函数表达式(IIFE)

    Immediately-Invoked Function Expression

    在 JavaScript 中,圆括号

    ()
    是一种运算符,跟在函数名之后,表示调用该函数。比如,
    print()
    就表示调用
    print
    函数。

    // 语句
    function f() {}
    
    // 表达式
    var f = function f() {}
    1. JavaScript 引擎规定,如果
      function
      关键字出现在行首,一律解释成语句
    2. 不让
      function
      出现在行首,则解释为表达式
    (function(){ /* code */ }());
    // 或者
    (function(){ /* code */ })();

    通常情况下,只对匿名函数使用这种“立即执行的函数表达式”。它的目的有两个:一是不必为函数命名,避免了污染全局变量;二是 IIFE 内部形成了一个单独的作用域,可以封装一些外部无法读取的私有变量。

    6. eval命令

    eval 以独立存在有意义的字符串为参数,并执行,否则报错
    eval的作用域为当前作用域,所以会造成变量污染; 严格模式下eval内部声明的变量不会影响外部作用域,但依然可以访问外部作用域的变量.依然会有安全风险

    (function f() {
    'use strict';//使用严格模式
    eval('var foo = 123');
    console.log(foo);  // ReferenceError: foo is not defined
    })()
    (function f() {
    'use strict';
    var foo = 1;
    eval('foo = 2');
    console.log(foo);  // 2
    })()

    eval的参数如果不是字符串,则原样返回

    eval(123);//123

    eval的别名调用作用域为全局作用域,即使在函数内部,依然为全局作用域

    6.1 应用场景

    从服务器动态获取代码来执行;可能会有被攻击者通过eval代码注入导致风险

    感谢补充与修改建议
    参考链接:
    函数提升
    eval不是魔鬼
    Javascript教程
    JS严格模式

    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: