js

109 阅读6分钟

1、ECMAScript-262核心规范及v8运行机制

  • js中9大数据类型以及堆栈内存
  • EC/VO/GO/scope/scope-chain等规范机制
  • GC垃圾回收、内存泄漏及闭包作用域机制
  • ES6混合模式下的v8词法分析和变量提升机制
  • 函数设计规范:普通函数、构造函数、箭头函数、生成器函数、静态对象
  • 面向对象OOP的底层设计原则:prototype/_ proto _
  • v8渲染页面的全套机制及DOM性能优化
  • 同步异步编程及EventLoop事件循环机制
  • 事件对象/事件传播/事件代理等处理机制
  • js中的this处理五大原则

1.1数据类型

  • 原始值类型(值类型/基本数据类型)
  1. number 数字 1、2、0、1.2 Infinity(无限值 -Infinity) NaN(不是一个数,是number类型) NaN === NaN ->false Object.is(NaN,NaN)->true 检测是否未有效数字的方法
if (Object.is(num,NaN)) {
    // num就是NaN num不是有效数字
}

// 浏览器提供的内置方法isNaN 是有效数字返回false 否则返回true 项目里主要使用这种方式
if (isNaN(num)) {
    // 先将num隐式转为number类型然后判断是不是NaN
}
  1. string 字符串 '' "" es6``模版字符串

  2. boolean 布尔 true false

  3. null 空对象指针

  4. undefined 未定义

  5. symbol 唯一值 只能是个函数,不能当作构造函数 所以不能new

    Symbol() === Symbol() -->false

    Symbol('A') === Symbol('A') -->false

    作用1:可以给对象设置唯一值类型的属性---对象的属性类型:string、symbol

    let a = [10,20];
    // 如果想访问到obj中Symbol类型的key的值
    let sym = Symbol('BB')
    let obj = {
        name: 'lele',
        age: 26,
        0: 100,
        // 特殊类型数据作为key 需要用[]包起来
        [{xxx: 'xxx'}]: 200,  // "[object object]": 200
        // a 的数值[10,20]作为key
        [a]: 300,  // '10,20': 300   
        [Symbol('AA')]: 400,
        [sym]: 500
    };
    console.log(obj['name']) // lele
    console.log(obj['age']) // 26
    console.log(obj[0]) // 100
    console.log(obj['0']) // 100
    console.log(obj[Symbol('AA')]) // undefined
    console.log(obj[sym]) // 500
    // 迭代
    for (let key in obj) { 
        // for in 循环是无法迭代symbol 类型的私有属性
        console.log(key);
    }
    // 获取非symbol类型的私有属性 返回一个数组
    let keys = Object.keys(obj)
     // 获取symbol类型的私有属性 返回一个数组
    let symKeys = Object.getOwnPropertySymbols(obj)
    keys = keys.concat(symKeys);
    // 第二种方法通过es6的Reflect.ownKeys获取所有的私有属性
    let keys = Reflect.ownKeys(obj)

作用2:把Symbol作为对象,提供的很多静态属性方法,是js很多的知识的底层实现原理 Symbol.toPrimitive/hasInstance/toString/interator/asyncIterator..... 作用3:vuex/redux中我们需要派发很多行为标识,我们可以把这些行为标识统一管理,为了行为保证标识的唯一性,所以可以基于symbol进行管理

  1. bigint 大数 Number.MAX_SAFE_INTETGER 最大安全数字 9007199254740991 超过这个数字进行运算,运算结果不一定准确
  • 对象类型(引用数据类型)
  1. 标准普通对象 object
  2. 标准特殊对象 Array、RegExp、Date、Math、Error.......
  3. 非标准特殊对象 Number、String、Boolean......
  4. 可调用/执行对象 函数 function

1.2数据类型检测

数据类型的检测方式

  • typeof [value] 返回值是字符串,字符串中包含所属的类型 typeof 检测对象类型,除函数被识别为'function',其余都是'object',不能细分对象,检测未被声明的变量不会报错,typeof xxx 结果是'undefined',为啥会这样呢???

@1 js中创建的所有类型值,在计算机底层都是按照二进制形式进行存储的

@2 typeof检测也是根据二进制值进行检查,其中有一条规则:如果以‘000’开始的二进制,则被识别为对象(null存储的二进制值都是0,符合以000开始);然后再去看对象是否实现了[[call]],实现了则为函数返回‘function',没有实现就返回‘object';因为按照二进制值进行检测速度更快

  • 000 对象
  • 1 整数
  • 010 浮点数
  • 100 字符串
  • 110 布尔
  • 000000 null
  • -2^30 undefined
  1. typeof typeof typeof [1,2,3] --->'string'
  2. typeof 12 --->'number'
  3. typeof 'lele' --->'string'
  4. typeof true --->'boolean'
  5. typeof null --->'object'
  6. typeof undefined --->'undefined'
  7. typeof Symbol() ---> 'symbol'
  8. typeof 10n ---> 'bigint'
  9. typeof [] ---> 'object'
  10. typeof {} ---> 'object'
  11. typeof /^$/ ---> 'object'
  12. typeof function(){} ---> 'function'
// 检测是否为对象 
// 方案一
if (value !== null && typeof value === 'object' || typeof value === 'function') {}
// 方案二
if (value !== null && /^(object | function)$/i.test(typeof value)) {}
  • Object.prototype.toString.call([value])
  • [value].instanceof [Constructor]
  • [vlaue].constructor
  • Array.isArray([value])
  • isNaN([value])

1.3数据类型转换

  • 隐式转换:一般用于浏览器的隐式转换中 Number()先转为数字
  1. 数学运算 10 - '2' = 8
  2. isNaN检测
  3. == 比较
  • 规则:
  1. 字符串转为数字:空字符串变为0,如果出现非有效数字字符,结果都是NaN Number('') === 0, Number('10') === 10, Number('10px') === NaN
  2. 布尔转为数字: Number(true) === 1, Number(false) === 0
  3. null是0,undefined是NaN Number(null) === 0, Number(undefined) === NaN
  4. Symbol无法转为数字
  5. 对象转数字:
  • 先调用对象的Symbol.toPrimitive('number') 这个方法,如果这个方法不存在
    // 标准普通对象
    let time = new Date(); 日期对象
    dir(time)
    time[Symbol.toPrimitive]('number') 时间戳
    // 数组
    let arr = [10]
    arr[Symbol.toPrimitive]-------->undefined
    arr.valueOf()------->[10]
    arr.toString()------>'10'
    Number(arr)----->10
  • 调用对象的valueOf() 获取原始值,如果获取的不是原始值
  • 调用对象的toString() 变成字符串
  • 最后把字符串基于Number方法转为数字
  • parseInt(val,radix) 1、val必须是字符串,如果不是,要先隐式转换为字符串 String(val)

2、radix 进制:如果不写,或者为0,默认是10(如果字符串是以0x开始的,默认值是16)

3、有效范围:2-36之间

4、从val左侧第一个字符开始查找,查找出符合radix进制的值(如果遇到不符合的则结束查找,不论后面是否还有符合的),把找到的内容,按照radix进制,转换为10进制

5、parseInt(val,10)严谨写法,否则会出现异常情况

    console.log(parseInt('10102px13',2)); //10
    //找到符合二进制的'1010'
    //把这个二进制的值转换为10进制“按权展开求和”
    //1*2^3+0*2^2+1*2^1+0*2^0 === 10
    console.log(parseInt(27.2,0)); //27
    console.log(parseInt(27.2,1)); //NaN 第二个参数需要2-36之间
    
  • 其它类型转布尔

除了0/NaN/空字符串/null/undefined是false,其余都是true

![] === false

!! [] === true 两个叹号相当于Boolean转为布尔类型

  • 两个等号== 1、对象==字符串 对象转为字符串

2、null==undefined true null/undefined和其他任何值都不相等

3、对象==对象 比较堆内存地址,地址相同则相等

4、NaN!==NaN

5、除了以上情况,只要两边类型不一致,都是先转为数字,然后再进行比较

6、=== 绝对相等,如果两边类型不同,则直接是false

  • 浮点数计算的解决方案 1、toFixed保留小数点后面N位,自动会四舍五入

2、扩大系数法

    // 获取系数
    const coeddicient = num => {
        num = num + '';
        let [,char = '']=num.split('.');
        let len = char.length;
        return Math.pow(10,len); // 10**len
    }
    const plus = (num1,num2){
        num1 = +num1;
        num2 = +num2;
        if(isNaN(num1) || isNaN(num2)) return NaN;
        let max = Math.max(coeddicient(num1),oeddicient (num2));
        return (num1*max + num2*max)/max;
    }
    console.log(plus(0.1,0.23)) //0.33
    a=?
    if(a==1 && a==2 && a==3){
        console.log('ok')
    }
    
    // 重写对象Symbol.toPrimitive
    a={
        i:0,
        [Symbol.toPrimitive](){
            return ++this.i;
        }
    }

1.4堆栈内存及函数底层处理机制