最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 前端知识体系-变量和类型

    正文概述 掘金(今晚打老虎i2016)   2020-12-05   366

    [toc]

    github地址

    js的变量和数据类型

    js的数据类型分为:原始类型(即基本类型)和对象类型(即引用数据类型)

    • 基本类型:
      • UndefinedNullNumberBooleanStringSymbol
    • 引用数据类型:
      • ObjectArrayFunctionDateRegExp等等

    一、基本类型和引用数据类型的区别

    基本类型

    • 基本类型不能由属性

      let name = 'Tom';
      name.age = 18;
        
      console.log(name.age) // undefined
      
      // 只有引用值可以动态添加后面的属性
      let name = new Sttring('Tom')
      // name -> String {"Tom"}
      name.age = 18
      console.log(name.age) // 18
      // name -> String {"Tom", age: 19}
        
      typeof name // "object"
      
    • 基本类型的值是不变的

      let name = 'tom'
      name.toUpperCase() // "TOM"
      name // tom
      
    • 基本类型是按值传递

      let name = 'tom';
      let name2 = 'TOM';
      name = name2;
      console.log(name, name2) // TOM TOM
      
    • 基本类型的比较是比较它们的值

      let a = 1;
      let b = true;
        
      a == b // true
      a === b // false
      
    • 基本类型的变量是存放在stack(栈)

      let a = 'tom';
      let b = 123;
      

    前端知识体系-变量和类型

    引用类型

    • 引用类型的值是可变

      const obj = {
        name: 'tom',
        age: 18
      }
      obj.sex = 'man';
      obj.getName = function () {
        console.log(this.name)
      }
      
    • 引用类型的比较是引用的比较

      const o1 = {};
      const o2 = {};
        
      o1 === o2 // false
      o1 == o2 // false
      

      o1o2 引用分别放在堆内存中的2个对象

    • 引用是类型的值是保存在堆内存中,指针存在栈中。

      前端知识体系-变量和类型

    一道题实战

    function addNum (num) {
        num += 1;
        return num
    }
    
    let count = 10;
    
    let result = addNum(count);
    
    console.log(count); // 10
    console.log(result) // 11
    
    
    function setPhone (obj) {
        obj.phone = '123'
    }
    
    let p1 = new Object();
    setPhone(p1)
    console.log(p1) // {phone: '123'}
    
    
    function setPhone (obj) {
        obj.phone = '123'
        // 创建一个新的对象
        obj = new Object();
        obj.phone = '456'
    }
    
    let p1 = new Object();
    setPhone(p1)
    
    console.log(p1) // {phone: '123'}
    

    二、类型检测

    • typeof
      • 只能检测基本数据类型 但是typeof null 是"object",不能检测复杂类型
    • instanceof 通过原型链去查找的
      • 返回的是false 或者true
      • 可以识别内置对象类型、自定义类型及其父类型
      • 不能识别标准类型,会返回false
      • 不能识别undefined、null,会报错
    • constructor属性 实例对象的constructor属性指向其构造函数。如果是内置类型,则输出function 数据类型(){[native code]};如果是自定义类型,则输出function 数据类型(){}
      • 可以识别标准类型、内置对象类型及自定义类型
      • 不能识别undefinednul,会报错,因为它俩没有构造函数
    • Object.prototype.toString() 返回 [object 数据类型]
      • 可以识别标准类型及内置对象类型
      • 不能识别自定义类型
    • Array.isArray() 数组的检测

    typeof

    typeof只能判断基本数据类型,不能判断引用数据类型(返回 object

    let s = 'tom';
    let num = 123;
    let bool = true;
    let sy = Symbol('tom')
    let u;
    let n = null;
    let o = new Object();
    
    
    typeof s    // string
    typeof num  // number
    typeof bool // boolean
    typeof u    // undefined
    typeof sy   // symbol
    
    typeof n    // object
    typeof o    // object
    

    注意typeof null object

    为什么typeof null object

    在 JavaScript 中 typeof null 的结果为 "object",这是从 JavaScript 的第一版遗留至今的一个 bug。在第一版的 JavaScript 中,变量的值被设计保存在一个 32 位的内存单元中。该单元包含一个 1 或 3 位的类型标志,和实际数据的值。类型标志存储在单元的最后。

    数据类型机器码标识
    整数1浮点数010字符串100布尔110undefined-2^31(即全为1)null全为0对象(Object)000

    在判断数据类型时,是根据机器码低位标识来判断的,而null的机器码标识为全0,而对象的机器码低位标识为000。所以typeof null的结果被误判为Object

    instanceof

    • 通过原型链去查找的
    • 返回的是false 或者true
    • 可以识别内置对象类型、自定义类型及其父类型
    • 不能识别标准类型,会返回false
    • 不能识别undefined、null,会报错
    'a' instanceof String -> false
    12 instanceof Number -> false
    true instanceof Boolean -> false
    undefined instanceof Undefined  ->报错
    [] instanceof Array -> true
    new Person instanceof Person -> true
    new Person instanceof Object -> true
    

    constructor

    constructor属性 实例对象的constructor属性指向其构造函数。如果是内置类型,则输出function 数据类型(){[native code]};如果是自定义类型,则输出function 数据类型(){}

    • 可以识别标准类型、内置对象类型及自定义类型
    • 不能识别undefinednul,会报错,因为它俩没有构造函数
    ('a').constructor -> function String(){[native code]}
    (undefined).constructor) -> 报错
    null).constructor -> 报错
    {name: "jerry"}).constructor -> function Object(){[native code]}
    (new Person).constructor -> function Person(){}
    // 封装成一个类型识别函数
    function type(obj){
      var temp = obj.constructor.toString();
      return temp.replace(/^function (\w+)\(\).+$/,'$1');
    }
    

    Object.prototype.toString()

    Object.prototype.toString() 返回 [object 数据类型]

    • 可以识别标准类型及内置对象类型
    • 不能识别自定义类型
    Object.prototype.toString.call('a') -> [object String]
    Object.prototype.toString.call(undefined) -> [object Undefined]
    Object.prototype.toString.call(null) -> Null
    Object.prototype.toString.call({name: "jerry"})) ->object Object]
    Object.prototype.toString.call(function(){}) -> [object Function]
    Object.prototype.toString.call(new Person)) -> [object Object]
    

    封装成一个类型识别函数

     function type(obj){
       return Object.prototype.toString.call(obj).slice(8,-1).toLowerCase();
     }
    

    Array.isArray()

    ​ 数组检测

    const a = [1,2,3]
    Array.isArray(a) -> true
    Array.isArray([]) -> true
    

    三、其他

    1.undefinednull的区别

    • nullundefined都是基本数据类型。

    • Undefined类型只有一个值,就是undefined。当声明的变量未初始化时,该变量的默认值是undefined。所以一般地,undefined表示变量没有初始化。

    • Null类型只有一个值,就是nullnulljavascript语言的关键字,它表示一个特殊值,常用来描述"空值",逻辑角度看,null值表示一个空对象指针

    null == undefined -> ture
    null === undefined -> false
    null === null -> true
    null == null -> true
    undefined === undefined -> true
    
    给一个全局变量赋值为`null`,相当于将这个变量的指针对象以及值清空,如果是给对象的属性赋值为`nul`l,或者局部变量赋值为`null`,相当于给这个属性分配了一块空的内存,然后值为`null`,` JS`会回收全局变量为`null`的对象。
    
    给一个全局变量赋值为`undefined`,相当于将这个对象的值清空,但是这个对象依旧存在,如果是给对象的属性赋值为`undefined`,说明这个值为空值
    

    扩展下

    ​ 声明了一个变量,但未对其初始化时,这个变量的值就是undefined,它是 JavaScript 基本类型 之一

    var data;
    console.log(data === undefined); //true
    

    ​ 对于尚未声明过的变量,只能执行一项操作,即使用typeof操作符检测其数据类型,使用其他的操作都会报错。

    //data变量未定义
    console.log(typeof data); // "undefined"
    console.log(data === undefined); //报错
    

    null 特指对象的值未设置,它是 JavaScript 基本类型 之一。

    null 是一个字面量,它不像undefined 是全局对象的一个属性。null 是表示缺少的标识,指示变量未指向任何对象。

    // foo不存在,它从来没有被定义过或者是初始化过:
    foo;
    "ReferenceError: foo is not defined"
    // foo现在已经是知存在的,但是它没有类型或者是值:
    var foo = null; 
    console.log(foo);   // null
    

    2.JavaScript中的变量在内存中的具体存储形式

    • 基本类型 --> 保存在内存中,因为这些类型在内存中分别占有固定大小的空间,通过按值来访问。基本类型一共有6种:UndefinedNullBooleanNumberStringSymbol
    • 引用类型 --> 保存在内存中,因为这种值的大小不固定,因此不能把它们保存到栈内存中,但内存地址大小的固定的,因此保存在堆内存中,在栈内存中存放的只是该对象的访问地址。当查询引用类型的变量时, 先从栈中读取内存地址, 然后再通过地址找到堆中的值。对于这种,我们把它叫做按引用访问。

    前端知识体系-变量和类型

    3.JavaScript对象的底层数据结构是什么

    参考链接1 参考链接2

    4.Symbol类型在实际开发中的应用、可手动实现一个简单的 Symbol

    ES6 的 Symbol 类型及使用案例

    5.javascript隐性转换

    在 JS 中基本数据类型之间的转化只有三种情况:

    • 转换为布尔值
    • 转换为数字
    • 转换为字符串

    前端知识体系-变量和类型

    上图中包含了所有转换规则,这里总结几点需要注意的地方:

    • NaNnumber 类型的数据,所以 number 转其他类型时不要漏掉它。
    • 对象转字符串,结果为:[object Object]
    • 数组转数字的规则:空数组、只有一个数字元素的数组转为数字,其余情况均为 NaN
    • undefinednull 转数字,分别为:NaN0
    • 转为 Boolean 时,除了 undefinednullfalseNaN0-0 转为 false,其他的都转为 true,包括所有对象。

    对于对象转换为基本类型时,其内部的原理如下:

    1. 如果已经是基本类型,直接返回
    2. 调用内置的 valueOftoString方法,如果转换为基本类型,则返回转换的值
    3. 如果没有转换为基本类型,则会抛出错误

    类型转换的一些小技巧

    • 数据前置 + 号,转换为 number 类型
    • 数据与 0 相减,转换为 number 类型
    • 数据前置 !! 号,转换为 Boolean 类型

    coding

        // 一、只有 + 两边有一边是字符串, 会把其它数据类型调用toString()方法转成字符串然后拼接
        // + 是字符串连接符: String(1) + 'true' = '1true'
        1 + "true"  // '1true'
    
        // 二、算术运算符+ :会把其它数据类型调用Number()方法转成数字然后做加法计算
        // + 是算法运算 1 + Number(true)
        1 + true // 2
        // 1 + Number(undefined) = 1 + NaN = NaN
        1 + undefined //NaN
        // 1 + Number(null) = 1+ 0 =1
        1 + null // 1
    
        // 三、关系运算符 会把其他数据类型转换成number之后再比较关系
    
        // 1.当关系运算符两边又一边是字符串时,会将其它数据类型使用Number()转换,然后比较关系
        // Number('2') > 10 = 2 > 10 = false
        '2' > 10 // false
        // 2.当关系运算符两边都是字符串,此时同时转成number然后比较关系
        // 重点:此时并不是按照Number()的形式转成数字,而是按照字符串对应的unicode编码转成数字
        // 使用这个查看字符串的unicode编码: 字符串的charCodeAt(字符下标,默认为0)
        // '2'.charCodeAt() > '10'.charCodeAt() = 50 > 49 = true
        '2' > '10' // true
        // 多个字符从左往右依次比较
        // 先比较'a' 和 'b', ‘a' 与 ‘b'不等,则直接得出结果
        "abc" > "b" //fasle
        // 先比较'a' 和'a',两者相等,继续比较第二个字符'b'与‘a',得出结果 a.charCodeA = 97 b.charCodeB=98
        "abc" > "aad" // true
        // 3.特殊情况:如果数据类型是undefined与null,得出固定的结果
        undefined == undefined // true
        undefined === undefined // true
        undefined == null // true
        null == null // ture
        null === null // ture
        // 4.NaN与任何数据比较都是NaN
        NaN == NaN // false
    
        //四、复杂数据类型在隐式转换时,
        // 如果是转换成number
        //1、如果输入的值已经是一个原始值,则直接返回它
        // 2、否则,如果输入的值是一个对象,则调用该对象的valueOf()方法,
        // 如果valueOf()方法的返回值是一个原始值,则返回这个原始值。
        // 3、否则,调用这个对象的toString()方法,如果toString()方法返回的是一个原始值,则返回这个原始值。
        // 4、否则,抛出TypeError异常。
    
        // 如果是转换成string
        // 1、如果输入的值已经是一个原始值,则直接返回它
        // 2、否则,调用这个对象的toString()方法,如果toString()方法返回的是一个原始值,则返回这个原始值。
        // 3、否则,如果输入的值是一个对象,则调用该对象的valueOf()方法,
        // 如果valueOf()方法的返回值是一个原始值,则返回这个原始值。
        // 4、否则,抛出TypeError异常。
    
        //复杂数据类型转number顺序如下
        // 1.先使用valueOf()方法获取其原始值,如果原始值不是number类型,则使用toString()方法转换成string
        // 2.再将string 转换成 number运算。
        [1,2] == '1,2' // true  [1,2]转换成string [1,2].valueOf() -> [1,2] [1,2].toString() -> '1,2'
    
        var a  = {}
        a == "[object Object]" // true a.valueOf().toString() -> "[object Object]"
    
        // 一道题
        var a = ???
        if(a==1 && a==2 &&a==3) {
            console.log(1)
        }
        // 如何完善a,使其正确打印1
    
        var a = {
            i: 0, //声明一个属性i
            valueOf: function() {
                return ++ a.i //每次调用一次,让对象a的i属性自增一次并且返回
            }
        }
        if(a==1 && a==2 &&a==3) { // 每次运算时都会调用一次a的valueOf方法
            console.log(1)
        }
    
        // 五、逻辑非隐形转换与关系元算符隐式转换搞混淆
        // 空数组的toString()方法会得到空字符串,而空对象的toString()方法会得到字符串'[object Object]'
    
        // 1.关系运算法:将其它数据类型转成数字
        // 2.逻辑非:将其它数据类型使用Boolean()转成布尔类型
        //  以下八种情况转换为布尔类型会得到false
        // 0、-0、NaN、undefined、null、空字符、false、document.all()
    
        // [].valueOf().toString()得到空字符串 Number('') ==0 
        [] == 0 // ture
    
        //本质是 ![] 逻辑非与表达式结果与0比较关系
        // 1.逻辑非优先级高于关系运算法  ![] = false(空数组转布尔得到true,然后取反得到fasle)
        // 2.false == 0 成立
        ![] == 0 // true
    
        // 本质其实是空对象{} 与 !{} 这个逻辑非表达式结果做比较
        //1.{}.valueOf().toString()得到字符串'[object Object]'
        //2.!{} = false
        //3.Number('[object Object]') -> NaN == Number(false) -> 0
        {} == !{}
    
        //引用类型数据存在堆中,栈中存储的是地址,所以他们的结果false
        {} == {} // false
    
        // 本质是空数组[] 与 ![] 这个逻辑表达式结果做比较
        //1. [].valueOf().toString()得到空字符串
        //2. ![] = false
        //3.Number('') == Number(false) 成立 都是0
        [] == ![] // true
    
        [] == [] // false 引用类型数据在堆中,栈中存储的是地址,所以他们的结果都是fasle
    
        {}.valueOf().toString() // [obejct Obejct]
        [].valueOf().toString() //空字符串
    

    掘金:你所忽略的js隐式转换

    6.0.1+-0.2===0.3?

    出现小数精度丢失的原因, JavaScript可以存储的最大数字、最大安全数字, JavaScript处理大数字的方法、避免精度丢失的方法

    0.1 + 0.2 !== 0.3 详细讲解

    7.== 和===

    对于 == 来说,如果对比双方的类型不一样的话,就会进行类型转换

    假如我们需要对比 xy 是否相同,就会进行如下判断流程:

    1. 首先会判断两者类型是否相同。相同的话就是比大小了

    2. 类型不相同的话,那么就会进行类型转换

    3. 会先判断是否在对比 nullundefined,是的话就会返回 true

    4. 判断两者类型是否为 stringnumber,是的话就会将字符串转换为 number

      1 == '1'
            ↓
      1 ==  1
      
    5. 判断其中一方是否为 boolean,是的话就会把 boolean 转为 number 再进行判断

      '1' == true
              ↓
      '1' ==  1
              ↓
       1  ==  1
      
    6. 判断其中一方是否为 object 且另一方为 stringnumber 或者 symbol,是的话就会把 object 转为原始类型再进行判断

      '1' == { name: 'tom' }
              ↓
      '1' == '[object Object]'
      

      流程图:

      前端知识体系-变量和类型

      1. 想了解更多的内容可以参考 标准文档。

      对于 === 来说就简单多了,就是判断两者类型和值是否相同

      [] !== [] // true
      

    8.varletconst区别

    var

    • var 命令会发生“变量提升”现象,即变量可以在声明之前使用,值为 undefined

      console.log(name);
      var name = 'tom'; // undefined
      
    • 内层变量可能覆盖外层变量

      var name = 'tom';
      {
        var name = 'TOM'
      }
        
      name // 'TOM'
      
    • 用来计数的循环变量泄露为全局变量

      for(var i = 0; i < 5; i++) {}
      
    • var不存在块级作用域

      {
        var name = 'tom';
      }
      console.log(name); // tom
        
      

    let

    • 声明的全局变量不会挂在顶层对象下面

    • let所声明的变量,只在let命令所在的代码块有效。

      {
        let a = 1;
        var b = 2
      }
      a // ReferenceError: a is not defined.
      b // 2
      
    • 变量的使用,一定要在声明前,否则会报引用错误(ReferenceError

      if (true) {
        let a;
      }
      console.log(a); // ReferenceError: a is not defined
      
    • letconst不允许在相同作用域内,重复声明同一个变量。

      //报错
      function func () {
        let name = 'tom';
        var name = 'TOM'
      }
        
      // 报错
      function func	() {
        let name = 'tom';
        let name = 'TOM';
      }
      
    • 暂时性死区,只要块级作用域内存在 let 命令,它所声明的变量就“绑定”( binding )这个区域,不再受外部的影响,在代码块内,使用 let 命令声明变量之前,该变量都是不可用的。

      var a = 1;
      if (true) {
        a = 2; // ReferenceError
        let a;
      }
      

    cosnt

    • 声明的全局变量不会挂在顶层对象下面

    • const 声明之后必须马上赋值,否则会报错

      const name  //Uncaught SyntaxError: Missing initializer in const declaration
      
    • const声明一个只读的常量。一旦声明,常量的值就不能改变。

      const NAME = 'TOM'
      NAME = 'tom'; // TypeError: Assignment to constant variable.
      
    • const 命令声明的常量也是不提升,同样存在暂时性死区,只能在声明的位置后面使用。

    9.varletconst原理

    • var

      会直接在栈内存里预分配内存空间,然后等到实际语句执行的时候,再存储对应的变量,如果传的是引用类型,那么会在堆内存里开辟一个内存空间存储实际内容,栈内存会存储一个指向堆内存的指针。

    • let

      是不会在栈内存里预分配内存空间,而且在栈内存分配变量时,做一个检查,如果已经有相同变量名存在就会报错。

    • const

      也不会预分配内存空间,在栈内存分配变量时也会做同样的检查。不过const存储的变量是不可修改的,对于基本类型来说你无法修改定义的值,对于引用类型来说你无法修改栈内存里分配的指针,但是你可以修改指针指向的对象里面的属性。


    起源地下载网 » 前端知识体系-变量和类型

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元