SakuraSnow's blog SakuraSnow's blog
首页
  • JavaScript
  • TypeScript
  • Vue
  • React
  • Git
  • Node
  • Linux
  • 技术文档
  • 博客搭建
  • 数据结构
  • leetcode
  • 关于
  • 友链
  • 收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

SakuraSnow

一只前端咸鱼
首页
  • JavaScript
  • TypeScript
  • Vue
  • React
  • Git
  • Node
  • Linux
  • 技术文档
  • 博客搭建
  • 数据结构
  • leetcode
  • 关于
  • 友链
  • 收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • JavaScript

    • JS变量知识回顾
    • TypeScript

    • 前端
    • JavaScript
    SakuraSnow
    2020-08-24

    JS变量知识回顾

    # 变量类型

    # 原始类型

    在JS中,变量分为原始类型和引用类型,其中原始类型有下面几种

    • number
    • string
    • boolean
    • null
    • undefined
    • symbol
    • BigInt(es10新增)

    # 引用类型

    引用类型也叫object类型,普通对象(Object),数组(Array), 函数(Function), 日期(Date)都是引用类型的一种

    # 变量的存储位置

    # 原始类型

    原始类型都是直接存放在栈中的,栈内存的特点如下

    • 存储的值大小固定
    • 空间较小
    • 可以直接操作其保存的变量,运行效率高
    • 由系统自动分配存储空间

    因为原始值一般不大,为了操作方便,所以会直接把数据存放在函数的执行栈里。在变量定义时,栈就为其分配好了内存空间。

    # 引用类型

    引用类型的值被存放在堆里,相对栈来说,堆有下面的特点

    • 存储的值大小不定,可动态调整
    • 空间较大,运行效率低
    • 无法直接操作其内部存储,使用引用地址读取
    • 通过代码进行分配空间

    而在栈中声明的变量,只是保存了一个指向堆里某个地址的指针

    file

    # 数据类型的判断

    # typeof操作符

    typeof在MDN文档中的描述如下

    file

    可以看出typeof判断大部分情况下还是没问题的,只是不太精确

    // Numbers
    typeof 37 === 'number';
    typeof Infinity === 'number';
    typeof NaN === 'number';   // Despite being "Not-A-Number"
    
    // Strings
    typeof '' === 'string';
    typeof 'bla' === 'string';
    
    // Booleans
    typeof true === 'boolean';
    typeof false === 'boolean';
    
    // Symbols
    typeof Symbol() === 'symbol'
    typeof Symbol('foo') === 'symbol'
    typeof Symbol.iterator === 'symbol'
    
    // Undefined
    typeof undefined === 'undefined';
    typeof declaredButUndefinedVariable === 'undefined';
    typeof undeclaredVariable === 'undefined';
    
    // Objects
    typeof {a: 1} === 'object';
    typeof [1, 2, 4] === 'object';
    typeof new Date() === 'object';
    typeof /regex/ === 'object';
    
    // Functions
    typeof function() {} === 'function';
    
    // bigint
    typeof 42n === 'bigint';
    
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36

    使用时只要记住,除了typeof null是'object',typeof function是'function',其他情况下都和JS中的变量分类一样就行了

    # instanceof操作符

    instanceof操作符主要用来检查构造函数的原型是否在对象的原型链上,也就是说只对引用类型有效, 不过当原型链被修改后,可能产生错误的判断

    // defining constructors
    function C() {}
    
    let o = new C()
    
    // true, because: Object.getPrototypeOf(o) === C.prototype
    o instanceof C
    
    
    o instanceof Object           // true
    
    C.prototype = {}
    let o2 = new C();
    
    o2 instanceof C  // true
    
    // false, because C.prototype is nowhere in
    // o's prototype chain anymore
    o instanceof C;
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

    instanceof对原始类型无效

    let simpleStr = 'This is a simple string'
    let myString  = new String()
    
    simpleStr instanceof String  // returns false, string literal is not an object
    myString  instanceof String  // returns true
    
    1
    2
    3
    4
    5

    # constructor属性

    function Animal (name) {
        this.name = name
    }
    
    const cat = new Animal('cat');
    
    console.log(cat.constructor === Animal)   // true
    
    1
    2
    3
    4
    5
    6
    7

    # toString方法

    function type (obj) {
        return Reflect.apply(Object.prototype.toString, obj, []).replace(/^\[object\s(\w+)\]$/, '$1').toLowerCase()
    }
    
    1
    2
    3

    这种方法基本可以判断所有的内置类型

    console.log(type(1))    // number
    console.log(type("123"))    // string
    console.log(type(true)) // boolean
    console.log(type(undefined))    // undefined
    console.log(type(null)) // null
    console.log(type(Symbol("s"))); // symbol
    console.log(type(11n));  // bigint
    console.log(type({}));  // object
    console.log(type([]));  // array
    console.log(type(function () {}));  // function
    console.log(type(/reg/));   // regexp
    console.log(type(new Date()));  // date
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

    但是对自定义的构造函数无效

    function Animal(name) {
        this.name = name;
    }
    
    console.log(type(new Animal("sena")));  // object
    
    1
    2
    3
    4
    5

    # toString方法 + Symbol.toStringTag

    我们可以设置es6中通过Symbol暴露的Symbol.toStringTag来改变toString的输出

    Animal.prototype[Symbol.toStringTag] = 'Animal';
    type(rabbit) // animal
    
    1
    2

    现在我们几乎可以用toString满足所有的需求了

    # 隐式类型转化规则

    转换前类型 转换前值 转换后(Boolean ) 转换后(Number) 转换后(String )
    Number 123 true - "123"
    Number Infinity true - "Infinity"
    Number 0 false - "0"
    Number NaN false - "NaN"
    BigInt 123456n true 123456 "123456"
    String "" false 0 -
    String "123" true 123 -
    String "123abc" true NaN -
    String ”abc” true NaN -
    Boolean ture - 1 "true"
    Boolean false - 0 "false"
    Undefined undefined false NaN "undefined"
    Null null false 0 "null"
    Object {} true NaN [object Object]
    Array [] true 0 ""
    Array ["abc"] true NaN "abc"
    Array ["abc", null] true NaN "abc,"
    Function function(){} true NaN "function(){}"
    Symbol Symbol() true TypeError TypeError

    file

    Boolean 转字符串这行结果我指的是 true 转字符串的例子,不是说 Boolean、函数、Symblo 转字符串都是 true

    在转换成Boolean时,除了 undefined, null, false, NaN, '', 0, -0,其他所有值都转为 true,包括所有对象。

    对象在转换类型的时候,会调用内置的 [[ToPrimitive]] 函数,对于该函数来说,算法逻辑一般来说如下:

    • 如果已经是原始类型了,那就不需要转换了
    • 如果需要转字符串类型就调用 x.toString(),转换为基础类型的话就返回转换的值。不是字符串类型的话就先调用 valueOf,结果不是基础类型的话再调用 toString
    • 调用 x.valueOf(),如果转换为基础类型,就返回转换的值
    • 如果都没有返回原始类型,就会报错
    • 你也可以重写 Symbol.toPrimitive ,该方法在转原始类型时调用优先级最高。

    # 四则运算符

    它的特点如下

    • 运算中其中一方为字符串,那么就会把另一方也转换为字符串
    • 如果一方不是字符串或者数字,那么会将它转换为数字或者字符串(优先数字)
    1 + '1' // '11'
    true + true // 2
    4 + [1,2,3] // "41,2,3"
    
    1
    2
    3

    # 类型比较

    之前写过了:https://www.sakura-snow.com/archives/142

    # 垃圾回收

    # 引用计数

    这是最初级的垃圾收集算法。此算法把“对象是否不再需要”简化定义为“对象有没有其他对象引用到它”。如果没有引用指向该对象,对象将被垃圾回收机制回收。

    function test(){
        var a = {} ;         // a的引用次数为0
        var b = a ;         // a的引用次数加1,为1
        var c =a;           // a的引用次数再加1,为2
        var b ={};          // a的引用次数减1,为1
    }
    
    1
    2
    3
    4
    5
    6

    但是这个算法有一个严重的问题,那就是循环引用

    function f(){
      var o = {};
      var o2 = {};
      o.a = o2; // o 引用 o2  o2的引用次数+1
      o2.a = o; // o2 引用 o  o的引用次数+1
    
      return "abc";
    }
    
    f();
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    在这个例子里,o和o2不会被回收,因为他们的引用次数都不为0。

    IE 6, 7使用引用计数方式对 DOM 对象进行垃圾回收。该方式常常造成对象被循环引用时内存发生泄漏

    var app;
    window.onload = function(){
    	app = document.getElementById("#app");
    	app.circularReference = app;
    	app.lotsOfData = new Array(10000).join("*");
    };
    
    1
    2
    3
    4
    5
    6

    因为app自己使用circularReference属性引用了自己,所以它的被引用次数始终不为0,即使被从dom树中删去也不会被回收,现在这种回收算法只有很老的浏览器才会使用了

    # 标记清除

    这个算法把“对象是否不再需要”简化定义为“对象是否可以获得”。算法假定设置一个叫做根(root)的对象(在Javascript里,根是全局对象)。垃圾回收器将定期从根开始,找所有从根开始引用的对象,然后找这些对象引用的对象……从根开始,垃圾回收器将找到所有可以获得的对象和收集所有不能获得的对象。

    这个算法的垃圾回收分为2个阶段,分别是标记和清除。

    • 标记 :从根节点开始标记引用的对象。
    • 清除 :未被标记引用的对象就是垃圾对象,可以被清理。

    从2012年起,所有现代浏览器都使用了标记-清除垃圾回收算法。

    # GC优化

    和其他语言一样,javascript的GC策略也无法避免一个问题:GC时,停止响应其他操作,这是为了安全考虑。而Javascript的GC在100ms甚至以上,对一般的应用还好,但对于JS游戏,动画对连贯性要求比较高的应用,就麻烦了。这就是新引擎需要优化的点:避免GC造成的长时间停止响应。

    # 分代回收

    这个和Java回收策略思想是一致的,也是V8所主要采用的。目的是通过区分“临时”与“持久”对象;多回收“临时对象”区(young generation),少回收“持久对象”区(tenured generation),减少每次需遍历的对象,从而减少每次GC的耗时。

    file

    # 增量GC

    这个方案的思想很简单,就是“每次处理一点,下次再处理一点,如此类推”。 file

    这种方案,虽然耗时短,但中断较多,带来了上下文切换频繁的问题。 因为每种方案都其适用场景和缺点,因此在实际应用中,会根据实际情况选择方案。

    #JavaScript#前端
    上次更新: 2022/03/05, 15:57:30
    TS怎么扩展原生类

    TS怎么扩展原生类→

    最近更新
    01
    009-Palindrome Number[回文数]
    03-10
    02
    008-String to Integer (atoi)[字符串转整数]
    03-10
    03
    004-Reverse-integer[整数反转]
    03-09
    更多文章>
    Theme by Vdoing | Copyright © 2019-2022 Evan Xu | MIT License
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式
    ×