JavaScript基础系列---变量及其值类型

基础概念

  • 变量是存储信息的容器,这里须要区分一下:变量不是指存储的信息自己,而是指这个用于存储信息的容器,能够把变量想象成一个个用来装东西的纸箱子
  • 变量须要声明,而且建议在声明的同时进行初始化,以下所示:node

    var aa = '1';
    let bb = 2;
    const CC = 3;
  • 若是从新声明变量,该变量的值不会丢失程序员

    var aa = 'cc';
    var aa; //此时的值仍是cc
  • 变量名(标志符)命名要求:es6

    • 适用于变量/属性/函数/函数参数的名字等
    • 可由字母、数字、下划线_及美圆符$组成
    • 不可使用关键字、保留字以及truefalsenull、(evalarguments严格模式下)
    • 使用undefined虽然不会报错,可是并不能声明成功,不管给它初始化为何,它的值仍然为undefined
    • 最好使用字母开头(还可使用_$

值类型

  • 变量可能包含两种不一样数据类型的值:基本类型值(简单的数据段)和引用类型值(可能由多个值构成的对象)
  • 由于全部引用类型的值都是Object的实例,因此可使用 xx instanceof Object 来判断是否为引用类型的值,若是是则会返回true,不然返回false
  • 存储方式segmentfault

    • 基本类型值在内存中占据固定大小空间,所以被保存在栈内存中(栈由操做系统自动分配释放);
    • 引用类型值是对象,保存在堆内存中;(堆:通常由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收)
  • 访问方式数组

    • 对于基本类型,变量存储的是具体的值,能够按值访问,直接操做存储的值
    • 对于引用类型,变量存储的是对象引用地址(指针),是按引用访问,当查询时,咱们须要先从栈中读取存储的内存地址,而后再顺藤摸瓜地找到保存在堆内存中的值
  • 复制变量值浏览器

    • 复制时,基本类型拷贝的是具体的值,而引用类型拷贝的是引用地址,因此引用类型赋值时要格外注意!!!
    //基本类型赋值
    var num1 = 10;
    var num2 = num1;
    console.log(num1,num2);// 10, 10
    num2 = 100;
    console.log(num1,num2);// 10, 100
    
    //引用类型赋值
    //person2拷贝了person1的引用地址,因此person1和person2实际上指向的是同一个对象
    //因此改变person2会影响到person1
    var person1 = {
        name:'cc'
    };
    var person2 = person1;
    console.log(person1.name, person2.name);// cc, cc
    person2.name = 'cshine';
    console.log(person1.name, person2.name);// cshine, cshine
    
    var arr1 = [1,2,3];
    var arr2 = arr1;
    console.log(arr1, arr2);// [1, 2, 3], [1, 2, 3]
    arr2[1]= 'string';
    console.log(arr1, arr2);// [1, "string", 3], [1, "string", 3]
  • 传递参数函数

    • ECMAScript中全部的函数的参数都是按值传递,即便是引用类型值的传递也是按值传递
    • 传递基本类型值时,被传递的值会被复制给一个局部变量(即命名参数或者arguments中的一个元素)
    • 传递引用类型值时,引用类型值是一个引用地址(指针),它也会复制给一个局部变量,这个局部变量再根据这个地址去按引用访问对象,所以这个局部变量的变化会反映在函数的外部。因此仍是按值传递,而不是由于它是按引用传递才致使局部变量的变化会反映在函数的外部

注意点

  • es6新增了letconst命令用来声明变量操作系统

    • let命令,它的用法相似于var,可是所声明的变量,只在let命令所在的块级做用域内有效,且在该块级做用域内不可重复声明
    • const声明一个只读的常量,一旦声明,常量的值就不能改变,与let同样,只在声明所在的块级做用域内有效,且在该块级做用域内不可重复声明
    • const实际上保证的,并非变量的值不得改动,而是变量指向的那个内存地址不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,所以等同于常量。但对于引用类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个引用地址(指针),const只能保证这个引用地址(指针)是固定的,至于它指向的堆内存中的存储的值是否是可变的,就彻底不能控制了。所以,将一个对象声明为常量必须很是当心。
  • 未使用var/let/const进行声明,此时建立的变量为全局变量,尽可能不要这样作!
  • var命令和function命令声明的全局变量,是顶层对象的属性,let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性(浏览器中为windownode中为global
  • 对于var/let来讲,只声明而未初始化,此时变量存储的信息是“空”的,也就是undefined;可是对于const来讲,只声明而不进行初始化是不容许的,会抛出Missing initializer in const declaration的错误,由于const定义的是常量,一旦定义便不可更改。

声明提高(hoisting

  • var命令声明的变量会发生”声明提高“现象,即变量能够在声明以前使用,值为undefined设计

    console.log(aa);// undefined
    var aa = 'string';
    console.log(aa);// string
  • function声明的函数也会发生”声明提高“现象,函数在声明以前可使用,值为指向该函数的指针;可是若是是在支持ES6的环境中,ES6容许在块级做用域内声明函数,此时在块级做用域中声明的函数,会提高到所在的块级做用域的头部,值为整个函数块,同时还会提高到块级做用域外,可是值为undefined。(环境致使块级做用域内声明函数的行为差别很是大,因此应该避免在块级做用域内声明函数。若是确实须要,也应该写成函数表达式,而不是函数声明语句)指针

    console.log(fn);// ƒ fn(){}
    function fn(){}
    console.log(fn);// ƒ fn(){}
    
    //支持es6的环境中
    console.log(fb);// undefined
    if(true){
        console.log(fb); // ƒ fb(){}
        function fb(){}
    }
    console.log(fb);// ƒ fb(){}
    
    console.log(fc);// undefined
    if(false){
        console.log(fc); // 未执行
        function fc(){}
    }
    console.log(fc);// undefined
    fc() //Uncaught TypeError: fc is not a function
  • 函数和变量都会声明提高,此时若函数名和变量名同名,函数名的优先级要高;可是正式执行代码时,同名函数会覆盖只声明却未赋值的变量,可是它不能覆盖声明且赋值的变量(缘由分析可见另外一篇文章JavaScript基础系列---执行环境与做用域链)

    console.log(bb);// ƒ bb(){}
    var bb;
    function bb(){}
    console.log(bb);// ƒ bb(){}
    
    
    console.log(cc);// ƒ cc(){}
    var cc = 'string';
    function cc(){}
    console.log(c)c;// string
  • 局部变量/函数(函数做用域function块里面的变量/函数)也会声明提高,能够先使用后声明,不影响外部同名变量/函数
  • letconst命令改变了语法行为,它们所声明的变量必定要在声明后使用,不然报错。因为letconst命令在当前块级做用域内不可重复声明因此当有同名函数时,会直接报错Identifier xx has already been declared

参考资料

相关文章
相关标签/搜索