JS+Vue初步学习

本文是自己学习中的随笔,如果有错误或者改进,欢迎指出。本文是学习https://wangdoc.com/javascript/types/null-undefined-boolean.html后的随笔,如果感兴趣,可以自己看一看

1.变量

  •  var 声明变量 如果声明(单纯声明,不赋值,赋值会覆盖前面声明的变量)一个已经存在的变量 是无效的(不会报错,也不会起作用)
  •  变量提升机制  所有变量的声明都会被提前,然后再一行一行的执行代码(所以如果在声明前使用了变量不会报错,会将其认为undefined)
  •  变量类型:Undefined、Null、Boolean、Number、String、Object
  •  null与undefined的区别:null是一个表示“空”的对象,转为数值时为0undefined是一个表示"此处无定义"的原始值,转为数值时为NaN 
    Number(null) // 0
    5 + null // 5
    
    Number(undefined) //NaN
    5 + undefined // NaN
    

    // 容易查出错误

  •  undefined表示“未定义”,它的主要应用场景如下:
    // 变量声明了,但没有赋值
    var i;
    i // undefined
    

    // 调用函数时,应该提供的参数没有提供,该参数等于 undefined
    function f(x) {
    return x;
    }
    f()
    // undefined

    // 对象没有赋值的属性
    var o = new Object();
    o.p
    // undefined

    // 函数没有返回值时,默认返回 undefined
    function f() {}
    f()
    // undefined

2.运算符

  •  相等运算符:===!====!=
  •  undefined、""或者''(空字符串)、null、false、0、NaN (转换为boolean是false,其余为true)
  •  空数组[] 与 空对象{} 转换为布尔值为true

3.数值

  •  JS中所有的数值都是以64位浮点数存储的,所以1与1.0是相同的 (某些运算只有整数才能完成,此时 JavaScript 会自动把64位浮点数,转成32位整数,然后再进行运算)
    1 === 1.0 // true

 

  •  由于浮点数不是精确的值,所以涉及小数的比较和运算要特别小心。
    0.1 + 0.2 === 0.3
    // false
    

    0.3 / 0.1
    // 2.9999999999999996

    (
    0.3 - 0.2) === (0.2 - 0.1)
    // false

    0.1 === 0.1
    // true

 

  •  超过-2^53 ~ 2^53 部分的数值,都无法保证精度,运算时结果会出错 (由于2的53次方是一个16位的十进制数值,所以简单的法则就是,JavaScript 对15位的十进制数都可以精确处理)
    Math.pow(2, 53)
    // 9007199254740992
    

    // 多出的三个有效数字,将无法保存
    9007199254740992111
    // 9007199254740992000

  •  根据标准,64位浮点数的指数部分的长度是11个二进制位。JavaScript 能够表示的数值范围为21024到2-1023(开区间),超出这个范围的数无法表示。
  •  如果一个数大于等于2的1024次方,那么就会发生“正向溢出”,返回Infinity
  •  如果一个数小于等于2的-1075次方(指数部分最小值-1023,再加上小数部分的52位),那么就会发生为“负向溢出”,会直接返回0。
    Math.pow(2, 1024) // Infinity
    Math.pow(2, -1075) // 0
    Number.MAX_VALUE // 1.7976931348623157e+308
    Number.MIN_VALUE // 5e-324
  •  数值的表示方法:
    123e3 // 123000
    123e-3 // 0.123
    -3.1E+12 // -3100000000000
    .1e-23 // 1e-24
  •  JavaScript 会自动将数值转为科学计数法表示:
    •  小数点前的零多于21位
    •  小数点后的零多于5位
  •  进制:通常来说,有前导0的数值会被视为八进制,但是如果前导0后面有数字8和9,则该数值被视为十进制(不会报错,严格的0o才会报错)(ES5严格模式和ES6已经废除0开头表示表示8进制,因为使用时很容易造成混淆)
    0888 // 888
    0777 // 511
    0o88 // 报错
  • JavaScript 内部实际上存在2个0:一个是+0,一个是-0,区别就是64位浮点数表示的符号位不同,它们是等价的,在使用过程中几乎都是当作0来使用
    -0 === +0 // true
    0 === -0 // true
    0 === +0 // true
    

    +0 // 0
    -0 // 0
    (-0).toString() // '0'
    (+0).toString() // '0'

    // 唯一有区别的场合是,+0或-0当作分母,返回的值是不相等的。
    (1 / +0) === (1 / -0) // fasle
    (1 / +0) // Infinity
    (1 / -0) // -Infinity

  •   NaN是 JavaScript 的特殊值,表示“非数字”(Not a Number),主要出现在将字符串解析成数字出错的场合。不是独立的数据类型,而是一个特殊数值,它的数据类型依然属于Number
    5 - 'x' // NaN
    // 将x转为数字出错
    

    // 一些运算函数的结果也为NaN
    Math.acos(2) // NaN 求取反余弦值。返回的值是 0 到 PI 之间的弧度值。
    Math.log(-1) // NaN 返回参数的自然数底数的对数值。
    Math.sqrt(-1) // NaN // 求根

    0 / 0 // NaN
    typeof NaN // 'number'

  •  NaN不等于任何数,包括它本身。数组的indexOf方法内部使用的是严格相等运算符,所以该方法对NaN不成立。NaN与任何数(包括它自己)的运算,得到的都是NaN。
    NaN === NaN // false
    
    [NaN].indexOf(NaN) // -1
    
    Boolean(NaN) // false
    
    NaN + 32 // NaN
    NaN - 32 // NaN
    NaN * 32 // NaN
    NaN / 32 // NaN
  •  Infinity表示“无穷”,用来表示两种场景。一种是一个正的数值太大,或一个负的数值太小,无法表示;另一种是非0数值除以0得到
    // 场景一
    Math.pow(2, 1024)
    // Infinity
    

    // 场景二
    0 / 0 // NaN
    1 / 0 // Infinity

  • Infinity大于任何数(除了NaN),-infinity小于任何数(除了NaN)。当与NaN比较时,总返回false
  • Infinity的运算:
    5 * Infinity // Infinity
    5 - Infinity // -Infinity
    Infinity / 5 // Infinity
    5 / Infinity // 0
    

    0 * Infinity // NaN
    0 / Infinity // 0
    Infinity / 0 // Infinity

    Infinity
    + Infinity // Infinity
    Infinity * Infinity // Infinity

    Infinity
    - Infinity // NaN
    Infinity / Infinity // NaN

    // Infinity与null计算时,null会转成0,等同于与0的计算。
    null * Infinity // NaN
    null / Infinity // 0
    Infinity / null // Infinity

    undefined
    + Infinity // NaN
    undefined - Infinity // NaN
    undefined * Infinity // NaN
    undefined / Infinity // NaN
    Infinity / undefined // NaN

  •  与数值相关的方法:parseInt() 将字符串转为整数 (字符串头部有空格,会自动去掉;参数不是字符串,会转换为字符串再转为整数)
    parseInt('123') // 123
    
    parseInt('   81') // 81
    
    parseInt(1.23) // 1
    // 等同于
    parseInt('1.23') // 1
    

    // 字符串转为整数的时候,是一个个字符依次转换,如果遇到不能转为数字的字符,就不再进行下去,返回已经转好的部分
    parseInt('8a') // 8
    parseInt('12**') // 12
    parseInt('12.34') // 12
    parseInt('15e2') // 15
    parseInt('15px') // 15

    // 如果字符串的第一个字符不能转化为数字(后面跟着数字的正负号除外),返回NaN
    parseInt('abc') // NaN
    parseInt('.3') // NaN
    parseInt('') // NaN
    parseInt('+') // NaN
    parseInt('+1') // 1

    // 如果字符串以0x或0X开头,parseInt会将其按照十六进制数解析。
    parseInt('0x10') // 16

    // 如果字符串以0开头,将其按照10进制解析。
    parseInt('011') // 11

    // 对于那些会自动转为科学计数法的数字,parseInt会将科学计数法的表示方法视为字符串,因此导致一些奇怪的结果。
    parseInt(1000000000000000000000.5) // 1
    //
    等同于
    parseInt('1e+21') // 1

    parseInt(
    0.0000008) // 8
    //
    等同于
    parseInt('8e-7') // 8

  •  parseInt()的进制转换:
    // parseInt方法还可以接受第二个参数(2到36之间),表示被解析的值的进制,返回该值对应的十进制数
    // 默认情况下,parseInt的第二个参数为10,即默认是十进制转十进制。
    parseInt('1000') // 1000
    // 等同于
    parseInt('1000', 10) // 1000
    
    parseInt('1000', 2) // 8
    parseInt('1000', 6) // 216
    parseInt('1000', 8) // 512
    

    // 如果第二个参数不是数值,会被自动转为一个整数。这个整数只有在2到36之间,才能得到有意义的结果,超出这个范围,则返回NaN。
    // 如果第二个参数是0、undefined和null,则直接忽略。 Number则不会忽略,直接转换失败返回NaN

    parseInt('10', 37) // NaN
    parseInt('10', 1) // NaN
    parseInt('10', 0) // 10
    parseInt('10', null) // 10
    parseInt('10', undefined) // 10

    parseInt(
    '1546', 2) // 1
    parseInt('546', 2) // NaN

    // 如果parseInt的第一个参数不是字符串,会被先转为字符串。这会导致一些令人意外的结果。
    parseInt(0x11, 36) // 43
    parseInt(0x11, 2) // 1

    // 等同于
    parseInt(String(0x11), 36)
    parseInt(String(
    0x11), 2)

    // 等同于
    parseInt('17', 36)
    parseInt(
    '17', 2)

    // 对于八进制的前缀0,尤其需要注意
    parseInt(011, 2) // NaN

    // 等同于
    parseInt(String(011), 2)

    // 等同于
    parseInt(String(9), 2)

    // JavaScript 不再允许将带有前缀0的数字视为八进制数,而是要求忽略这个0。
    // 但是,为了保证兼容性,大部分浏览器并没有部署这一条规定。

  •  parseFloat()方法,将字符串转为浮点数 parseFloat方法会自动过滤字符串前导的空格。
    // parseFloat会将空字符串转为NaN。
    // 这些特点使得parseFloat的转换结果不同于Number函数
    
    parseFloat([]) // NaN
    parseFloat('FF2') // NaN
    parseFloat('') // NaN
    
    parseFloat(true)  // NaN
    Number(true) // 1
    
    parseFloat(null) // NaN
    Number(null) // 0
    
    parseFloat('') // NaN
    Number('') // 0
    
    parseFloat('123.45#') // 123.45
    Number('123.45#') // NaN
    
    Number(undefined) // NaN
    parseFloat(undefined) // NaN

    Number([]) // 0
    Number({}) // NaN
  •  isNaN()方法:
    // isNaN只对数值有效,如果传入其他值,会被先转成数值。
    // 比如,传入字符串的时候,字符串会被先转成NaN,所以最后返回true,
    // isNaN为true的值,有可能不是NaN,而是一个字符串。
    
    isNaN('Hello') // true
    // 相当于
    isNaN(Number('Hello')) // true
    

    // 对象和数组
    isNaN({}) // true
    //
    等同于
    isNaN(Number({})) // true

    isNaN([
    'xzy']) // true
    //
    等同于
    isNaN(Number(['xzy'])) // true

    // 对于空数组和只有一个数值成员的数组,isNaN返回false
    isNaN([]) // false
    isNaN([123]) // false
    isNaN(['123']) // false

    // 自定义判断是否为NaN
    function myIsNaN(value) {
    return typeof value === 'number' && isNaN(value);
    }

    // 判断NaN更可靠的方法是,利用NaN为唯一不等于自身的值的这个特点,进行判断。
    function myIsNaN(value) {
    return value !== value;
    }

  •  isFinite()方法:返回一个布尔值,表示某个值是否为正常的数值
    isFinite(Infinity) // false
    isFinite(-Infinity) // false
    isFinite(NaN) // false
    isFinite(undefined) // false
    isFinite(null) // true
    isFinite(-1) // true
    

    //除了Infinity、-Infinity、NaN和undefined这几个值会返回false,
    //
    isFinite对于其他的数值都会返回true。

  •  JavaScript 返回的字符串长度可能是不正确的,因为JavaScript 对 UTF-16 的支持是不完整的,由于历史原因,只支持两字节的字符,不支持四字节的字符。对于码点在U+10000U+10FFFF之间的字符,JavaScript 总是认为它们是两个字符(length属性为2)。
  •     Base64编码 
    • btoa():任意值转为 Base64 编码
    • atob():Base64 编码转为原来的值
    • 注意,这两个方法不适合非 ASCII 码的字符,会报错
  • var string = 'Hello World!';
    btoa(string) // "SGVsbG8gV29ybGQh"
    atob('SGVsbG8gV29ybGQh') // "Hello World!"
    
    btoa('你好') // 报错
    

    // 要将非 ASCII 码字符转为 Base64 编码,必须中间插入一个转码环节,再使用这两个方法。
    function b64Encode(str) {
    return btoa(encodeURIComponent(str));
    }

    function b64Decode(str) {
    return decodeURIComponent(atob(str));
    }

    b64Encode('你好') // "JUU0JUJEJUEwJUU1JUE1JUJE"
    b64Decode('JUU0JUJEJUEwJUU1JUE1JUJE') // "你好"

  •  对象-键名 (如果是字符串,可以任意命名,包括空格;如果不是,则必须符合标识符规范或者为数值才会自动转换为字符串,否则报错)
    var o1 = {};
    var o2 = { bar: 'hello' };
    

    o1.foo = o2;
    o1.foo.bar
    // "hello"

    // 属性可以动态创建,不必在对象声明时就指定 如,没有在o1中声明foo属性,直接定义赋值使用
    // 对象的属性之间用逗号分隔,最后一个属性后面可以加逗号(trailing comma),也可以不加。
    // 对象中的值可以为任意数值或者函数。和Java中的对象意义上差不多,属性+方法

    { foo: 123 }
    // JavaScript 引擎读到上面这行代码,会发现可能有两种含义。
    // 第一种可能是,这是一个表达式,表示一个包含foo属性的对象;
    // 第二种可能是,这是一个语句,表示一个代码区块,里面有一个标签foo,指向表达式123。
    // 如果遇到这种情况,无法确定是对象还是代码块,一律解释为代码块
    

    // 这种差异在eval语句(作用是对字符串求值)中反映得最明显。
    eval('{foo: 123}') // 123
    eval('({foo: 123})') // {foo: 123}
    //
    上面代码中,如果没有圆括号,eval将其理解为一个代码块;加上圆括号以后,就理解成一个对象。

    属性的读取有两种,一种是obj.p,另一种是obj['p'];后面一种必须用引号括起,否则会当作变量处理(方括号内部还能使用表达式) 数值键名不能使用点式读取,会和小数点混淆

  •  查看一个对象本身的所有属性 Object.keys(obj)方法
  •  属性的删除 delete obj.p 或者 delete obj['p'] (删除一个对象中不存在的属性,不会报错,并且返回true;所以不能使用删除来判断对象是否存在;delete只有某个属性存在,并且不能删除的时候才返回为false)
    var obj = Object.defineProperty({}, 'p', {
      value: 123,
      configurable: false
    });
    

    obj.p // 123
    delete obj.p // false

    // delete命令只能删除对象本身的属性,无法删除继承的属性

    var obj = {};
    delete obj.toString // true
    obj.toString // function toString() { [native code] }
    // toString是对象obj继承的属性,虽然delete命令返回true,但该属性并没有被删除,依然存在。
    // 这个例子还说明,即使delete返回true,该属性依然可能读取到值
  •  属性是否存在:in运算符
    // in运算符用于检查对象是否包含某个属性(注意,检查的是键名,不是键值)
    // 如果包含就返回true,否则返回false
    // 它的左边是一个字符串,表示属性名,右边是一个对象。
    var obj = { p: 1 };
    'p' in obj // true
    'toString' in obj // true
    // 但是in不能识别哪些属性是对象自身的,哪些属性是继承的
    // 可以使用对象的hasOwnProperty方法判断一下,是否为对象自身的属性
    var obj = {};
    if ('toString' in obj) {
      console.log(obj.hasOwnProperty('toString')) // false
    }
  • 属性的遍历:for...in循环
    var obj = {a: 1, b: 2, c: 3};
    

    for (var i in obj) {
    console.log(
    '键名:', i);
    console.log(
    '键值:', obj[i]);
    }
    // 键名: a
    //
    键值: 1
    //
    键名: b
    //
    键值: 2
    //
    键名: c
    //
    键值: 3

    // 它遍历的是对象所有可遍历(enumerable)的属性,会跳过不可遍历的属性。
    //
    它不仅遍历对象自身的属性,还遍历继承的属性。
    var obj = {};

    // toString 属性是存在的
    obj.toString // toString() { [native code] } 默认是不可遍历的

    for (var p in obj) {
    console.log(p);
    }
    // 没有任何输出

    // 如果想遍历自身的属性,可以使用hasOwnProperty来辅助完成
    var person = { name: '老张' };

    for (var key in person) {
    if (person.hasOwnProperty(key)) {
    console.log(key);
    }
    }
    // name

  •  with语句,作用是操作同一个对象的多个属性时,提供一些书写的方便。
    // 格式
    with (对象) {
      语句;
    }
    

    // 举例
    //
    例一
    var obj = {
    p1:
    1,
    p2:
    2,
    };
    with (obj) {
    p1
    = 4;
    p2
    = 5;
    }
    // 等同于
    obj.p1 = 4;
    obj.p2
    = 5;

    // 例二
    with (document.links[0]){
    console.log(href);
    console.log(title);
    console.log(style);
    }
    // 等同于
    console.log(document.links[0].href);
    console.log(document.links[
    0].title);
    console.log(document.links[
    0].style);

    // 注意,如果with区块内部有变量的赋值操作,必须是当前对象已经存在的属性,否则会创造一个当前作用域的全局变量。

    var obj = {};
    with (obj) {
    p1
    = 4;
    p2
    = 5;
    }

    obj.p1 // undefined
    p1 // 4
    //
    应该先定义对象obj的属性p1,然后在with区块内操作它。
    //
    with没有改变作用域,它的内部依然是当前作用域,这造成了with绑定对象不明确

    // 建议不要使用with,使用临时变量代替
    with(obj1.obj2.obj3) {
    console.log(p1
    + p2);
    }

    // 可以写成
    var temp = obj1.obj2.obj3;
    console.log(temp.p1
    + temp.p2);

4.函数

  •  声明函数的方法有三种:
    •  function命令
      function print(s) {
        console.log(s);
      }
    •  函数表达式(赋值语句右侧只能是表达式)
      var print = function(s) {
        console.log(s);
      };
      

      // 后面的函数可以有函数名,但是只能在函数内部使用,函数外部无效
      var print = function x(){
      console.log(typeof x);
      };

      x
      // ReferenceError: x is not defined

      print()
      // function

      // 这种写法的用处有两个:
      // 一是可以在函数体内部调用自身,
      // 二是方便除错(除错工具显示函数调用栈时,将显示函数名,而不再显示这里是一个匿名函数)
      var f = function f() {}; // 也非常常见
      // {}结束后加分号,函数的声明,不需要加

    •  Function构造函数
      var add = new Function(
        'x',
        'y',
        'return x + y'
      );
      

      // 等同于
      function add(x, y) {
      return x + y;
      }

      // 上面代码中,Function构造函数接受三个参数,除了最后一个参数是add函数的“函数体”,其他参数都是add函数的参数。
      var foo = new Function(
      'return "hello world";'
      );

      // 等同于
      function foo() {
      return 'hello world';
      }

      // Function构造函数可以不使用new命令,返回结果完全一样。总的来说,这种声明函数的方式非常不直观,几乎无人使用。

  •  函数重复声明会覆盖前面的声明,而且函数名的提升机制(将函数视作变量,所以和变量相同的提升机制,将其放置到代码头部),致使一旦后面有覆盖的声明,前面在任何使用的时候都是被覆盖的,前面的声明完全无效;
    // 不会报错
    f();
    

    function f() {}

    // 但是,如果采用赋值语句定义函数,JavaScript 就会报错。
    f();
    var f = function (){};
    // TypeError: undefined is not a function

    // 等同于
    var f;
    f();
    f
    = function () {};

    // ~~~~~
    var f = function () {
    console.log(
    '1');
    }

    function f() {
    console.log(
    '2');
    }
    // 表面上后面声明的函数f,应该覆盖前面的var赋值语句,但是由于存在函数提升,实际上正好反过来。

    f()
    // 1

  •  函数继承的属性:
    •  name,获取函数名称
    •  length,返回函数预期传入的参数个数,即函数定义之中的参数个数。
    •  toString()方法,返回一个字符串,内容为函数的源代码;对于那些原生的函数,toString()方法返回function(){[native code]}。
  •  slice()方法,切割想要的部分;左闭右开。
  •  join()方法,用于将数组中的所有元素放入一个字符串中;有参数,参数即表示数组中的所有元素的间隔样式
  •  函数内部也有变量的提升(局部变量):不管变量声明在哪里,都会被提升到函数体的头部
  •  函数的参数不是必须的,JS允许省略参数;需要注意的是,函数的length属性与实际传入的参数个数无关,只反映函数预期传入的参数个数。但是,没有办法只省略靠前的参数,而保留靠后的参数。如果一定要省略靠前的参数,只有显式传入undefined。
    function f(a, b) {
      return a;
    }
    

    f( , 1) // SyntaxError: Unexpected token ,(…)
    f(undefined, 1) // undefined

  •  如果有同名的参数,则取后面出现的那个值
    function f(a, a) {
      console.log(a);
    }
    

    f(1, 2) // 2

    // 取值的时候,以后面的a为准,即使后面的a没有值或被省略,也是以其为准
    function f(a, a) {
    console.log(a);
    }

    f(1) // undefined

    // 如果要获得第一个a的值,可以使用arguments对象。

    function f(a, a) {
    console.log(arguments[
    0]);
    }

    f(1) // 1

  • 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
    //
    由于 JavaScript 允许函数有不定数目的参数,所以需要一种机制,可以在函数体内部读取所有参数。

    // 正常模式下,arguments对象可以在运行的时候修改
    var f = function(a, b) {
    arguments[
    0] = 3;
    arguments[
    1] = 2;
    return a + b;
    }

    f(1, 1) // 5

    // 严格模式下,arguments对象与函数参数不具有联动关系。也就是说,修改arguments对象不会影响到实际的函数参数。
    var f = function(a, b) {
    'use strict'; // 开启严格模式
    arguments[0] = 3;
    arguments[
    1] = 2;
    return a + b;
    }

    f(1, 1) // 2

    // 通过arguments对象的length属性,可以判断函数调用时到底带几个参数。
    function f() {
    return arguments.length;
    }

    f(1, 2, 3) // 3
    f(1) // 1
    f() // 0

    // 让arguments对象使用数组方法,真正的解决方法是将arguments转为真正的数组。下面是两种常用的转换方法:slice方法和逐一填入新数组。
    var args = Array.prototype.slice.call(arguments);

    // 或者
    var args = [];
    for (var i = 0; i < arguments.length; i++) {
    args.push(arguments[i]);
    }

  •  callee属性:arguments对象带有一个的属性,返回它所对应的原函数
    var f = function () {
      console.log(arguments.callee === f);
    }
    

    f() // true

    // 可以通过arguments.callee,达到调用函数自身的目的。这个属性在严格模式里面是禁用的,因此不建议使用。

  •  闭包:闭包的最大用处有两个,一个是可以读取函数内部的变量,另一个就是让这些变量始终保持在内存中,即闭包可以使得它诞生环境一直存在。请看下面的例子,闭包使得内部变量记住上一次调用时的运算结果。
    function createIncrementor(start) {
      return function () {
        return start++;
      };
    }
    

    var inc = createIncrementor(5);

    inc() // 5
    inc() // 6
    inc() // 7

  •  闭包的另一个用处,是封装对象的私有属性和私有方法。
    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

    // 注意
    外层函数每次运行,都会生成一个新的闭包,而这个闭包又会保留外层函数的内部变量,所以内存消耗很大。因此不能滥用闭包,否则会造成网页的性能问题。

  •  立即调用的函数表达式(IIFE):
    (function(){ /* code */ }());
    // 或者
    (function(){ /* code */ })();

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

  •  eval()方法:命令接受一个字符串作为参数,并将这个字符串当作语句执行。如果参数字符串无法当作语句运行,那么就会报错。
    eval('var a = 1;');
    a // 1
    
    eval('3x') 
    // Uncaught SyntaxError: Invalid or unexpected token
    

    // 放在eval中的字符串,应该有独自存在的意义,不能用来与eval以外的命令配合使用。举例来说,下面的代码将会报错。
    eval('return;');
    // Uncaught SyntaxError: Illegal return statement
    //
    return语句必须在函数中才能使用

    // 如果eval的参数不是字符串,那么会原样返回。
    eval(123) // 123

    // eval没有自己的作用域,都在当前作用域内执行,因此可能会修改当前作用域的变量的值,造成安全问题。

    var a = 1;
    eval(
    'a = 2');

    a // 2

    // JavaScript 规定,如果使用严格模式,eval内部声明的变量,不会影响到外部作用域。
    (function f() {
    'use strict';
    eval(
    'var foo = 123');
    console.log(foo);
    // ReferenceError: foo is not defined
    })()

    // 不过,即使在严格模式下,eval依然可以读写当前作用域的变量。
    (function f() {
    'use strict';
    var foo = 1;
    eval(
    'foo = 2');
    console.log(foo);
    // 2
    })()

但是,如果采用赋值语句定义函数,JavaScript 就会报错

posted @ 2020-07-14 08:59  Lilyyaya~  阅读(132)  评论(0)    收藏  举报