美文网首页工作生活
JS数据类型及操作原理

JS数据类型及操作原理

作者: 没了提心吊胆的稗子 | 来源:发表于2019-07-03 22:10 被阅读0次

    数据类型

    • 基本数据类型

      • number
      • string
      • boolean
      • null
      • undefined
      • symbol
    • 引用数据类型

      • 对象

        • {} 普通对象
        • []数组
        • /^$/ 正则
        • Math
      • 函数

        • function普通函数

    JS 代码运行在浏览器中,是因为浏览器提供了一个供JS代码执行的环境 -> 全局作用域(window/global)

    var a = 12, 
    var b = a;
    b = 13;
    cobsole.log(a); // 12
    
    var obj = {name: "lulu"};
    var p = obj;
    obj.name = "123";
    console.log(obj.name); // 123
    
    var m = {name:"javascript"};
    var n = m;
    n = {name:"前端开发"}; // n在这一步又指向别的空间,m和n就没关系了
    console.log(m.name); // javascript
    
    function fn(){
      var ary = Array.prototype.slice.call(arguments) // 把类数组转化成数组
      return eval(ary.join('+'));
    }
    
    

    值类型

    按值操作 如var a = 12; 直接把12这个值赋给变量a(让两者建立了链接关系)

    对象数据类型

    对象类型:
    1)浏览器为其开辟一个新的内存空间(不像值类型只有一个值,可以有很多的值),浏览器给空间分配一个16进制的地址,
    2)按照一定顺序,分别把对象键值对存储到内存空间中
    3)把这个地址赋值给引用类型变量,是两者关联,引用类型就可以通过该地址找到内存空间,对空间里面存储的值进行操作

    函数的操作

    创建函数(也是对象)

    1. 先开一个新的内存空间,为其分配一个16进制的地址(跟对象中的第一步别无二致)
    2. 把函数体中编写的js代码当作字符串存储到开辟的空间中(函数只创建不执行没啥意义)
    3. 把分配的地址赋值给声明的函数名(function fn和var fn操作原理相同,都是在当前作用域中声明了一个名字,重复)
      跟对象的区别:对象的内存中存的是有意义的字符串,而函数的内存中存的是无意义的字符串

    执行函数
    执行函数其中的代码

    1. 函数执行的时候浏览器会形成一个新的私有作用域(只能执行函数体中的代码)供函数体中的代码执行
    2. 执行代码之前,先把创建函数时存储的字符串变为真正的js表达式,按照从上到下的顺序在私有作用域中执行

    一个函数可以被执行很多次,每次执行相互之间互不干扰
    形成的二私有作用域把函数体中的私有变量都保护起来了,在私有作用域中操作私有变量和外界没有关系,外界也无法直接操作私有变量,函数执行的这种保护机制叫做闭包

    JS中的堆栈内存

    栈内存
    即作用域(全局作用域/私有作用域)
    [作用]

    • 为js代码提供执行的环境
    • 基本数据类型是直接存放在栈内存中的

    堆内存
    存储引用数据类型值的,相当于一个存储的仓库
    对象存储的是键值对
    函数存储的是代码字符串

    项目中内存越少越好,我们需要把一些没用的内存处理到
    [堆内存]
    var obj = {}; 当前对象对应的堆内存被变量obj占用,无法销毁
    obj = null; 空对象指针,不指向任何堆内存,谷歌浏览器会在空闲时间把没有被占用的堆内存自动释放(销毁/回收)
    [栈内存]
    一般情况下函数执行形成栈内存,若函数执行完成,浏览器会把形成的栈内存自动释放;有时候执行完成栈内存不能被释放
    全局作用域在加载页面时执行,关闭页面时销毁

    变量提升

    当前作用域中,js代码自上而下执行,浏览器首先会把var/function关键字进行提前的声明或者定义
    声明(declare): var num; 告诉当前作用域有这个名字了
    定义(defined): num = 21; 把声明的名字赋一个值
    var关键字的只是声明,function声明加定义一起完成

    console.log(num);
    console.log(fn);
    var num = 13;
    function fn(){
      console.log(a);
      var a = 10;
      console.log(a);
    }
    fn();
    console.log(num);
    

    变量声明时带var和不带的区别

    带var在当前作用域中创建了一个变量。(若当前是全局作用域,也会给全局作用域下添加这个属性)
    在全局作用域中不带var,仅是给全局对象设置了一个新的属性名,省略了window.

    // 带var
    // 变量提升 var a <=> window.a=undefined
    console.log(a); // ->undefined
    var a = 12;
    console.log(a); // ->
    console.log(window.a); // ->
    
    // 不带var
    console.log(a); // ReferenceError a is not defined 先看他是不是变量,不是,报错
    console.log(window.a) //->12
    a = 12; // <=> window.a
    console.log(window.a) //->12
    

    作用域链

    函数执行形成一个私有作用域,保护其中的私有变量,进入私有作用域中首先变量提升(声明过的变量是私有的),然后代码执行
    1、执行的时候遇到变量,若为私有,则按照私有处理即可

    function fn(){
        console.log(a); // undefined 私有变量
        var a = 12;
        console.log(a); // 12
    }
    fn();
    console.log(a); //全局下没有这个属性  报错
    

    2、如果当前这个变量不是私有的,需要向他的上级作用域进行查找,上级也没有就继续上一级,直到全局作用域,这种查找机制为作用域链
    1)如果上级有,在当前进行的操作则都会操作上级的那个变量
    2)若上级没有,一直找到window:
    变量 = 值 相当于给window设置了一个属性,

    console.log(x, y); // undefined, undefined
    var x= 10, y = 20;
    function fn2() {
        console.log(x, y); //undefined, 20
        var x = y = 100;
        console.log(x, y); // 100(私有) 100(全局)
    }
    console.log(x, y); // 10 100
    

    只对等号左边的进行变量提升

    =: 赋值,左边的是变量,右边都应是值
    匿名函数:函数表达式,把函数当作一个值赋给变量或者其他内容

    oDiv.onclick = function(){};
    // 相当于oDiv.onclick = aaafff111(函数地址)
    

    只对等号左边进行变量提升,右边就是一个值

    console.log(fn); // undefined
    var fn = function () {
    
    };
    console.log(fn); // [Function: fn]
    

    真是项目中应用这个原理,使用函数表达式创建函数
    1)只能对等号左边进行提升,变量完成之后,当前函数只是声明了没有定义,执行函数必须放在赋值代码之后
    2)可让代码更加严谨

    不管条件是否成立,都要进行变量提升

    console.log(num); // undefined
    console.log(fn); //undefined
    if(1 === 1){
        console.log(num); // undefined
        console.log(fn); // 函数体本身
        var num = 12;
        function fn() {
        }
        console.log(num); // 12
        console.log(fn); // 函数体本身
    }
    console.log(fn); // 函数体本身
    

    不管条件是否成立,判断体中出现的var, function都会进行变量提升,,在最新版本中,function只能提前声明,不能定义(因为不确定判断条件是否成立)
    [条件不成立]
    进不到判断体中,赋值的代码执行不了,之前声明的变量或者函数依然是undefined
    [条件成立]
    进入判断体的第一件事是把之前声明但未定义的函数先定义,然后以上而下执行代码
    但老版浏览器不管条件是否成立,都会进行函数声明加定义

    重名处理

    在变量提升阶段,若有重名,不会重新进行声明,但函数的定义会有替换(后替换前)

    私有变量

    1、私有作用域变量提升阶段,声明过的变量或者函数
    2、形参

    function add(arg1, arg2){
      var sum = arg1 + arg2; //  sum,arg1, arg2私有变量
      return sum;
    }
    var sum = add(10, 20); // sum公有
    

    上级作用域

    函数的上级作用域跟在哪执行的没关系,在哪定义上级作用域就是谁

    var n = 1;
    function fn(){
      console.log(n);
    }
    fn();  // 1
    (~function (){
      var n = 2;
      fn(); // 1 fn的宿主环境是当前自执行函数形成的私有作用域
    })();
    
    var p = 10;
    var obj = {
        p: 20,
        fn: (function () { 
            var p = 30;
            return function () { 
                console.log(p);
            }
        })()
    };
    // 执行的是return那个函数而不是自执行函数  
    // 函数的上级作用域是自执行函数
    obj.fn();   // 30
    
    var p = 10;
    var obj = {
        p: 20,
        fn: (function () { 
            return function () { 
                console.log(p);
            }
        })()
    };
    obj.fn(); // 10 自执行函数的上级作用域是全局作用域
    
    var p = 10;
    var obj = { 
        p: 20,
        fn: (function () { 
            return function (p) {
                console.log(p);
            }
        })(obj.p)
    };
    obj.fn(); // 报错 Cannot read property 'p' of undefined 
    // 自执行函数执行的时候还obj还没有赋值
    

    相关文章

      网友评论

        本文标题:JS数据类型及操作原理

        本文链接:https://www.haomeiwen.com/subject/ftgncctx.html