1、 js数据类型分为:原始类型和对象类型;
原始类型:boolean number string undefined null symbol bigint
对象类型:Object Function;
原始类型存储在栈上,对象类型存储在堆上,然而他的援用地址还是存在栈上。
?题型:对于对象的批改,往函数里传一个对象进去,函数外部批改参数,这类题目记住以下要点:
1、对象存储的是援用地址,传来传去、赋值给他人都是在传递值(存在栈上的内容),他人一旦批改对象里的属性,大家都被批改了;
2、然而对象一旦被赋值了,只有不是原对象被从新赋值,那么就永远不会批改原对象。
2、类型判断
1、typeof:原始类型中除了null,其余类型都能够通过typeof来判断。
(typeof null = obejct) => 长远的bug;
2、instanceof通过外部的原型链的形式来判断是否为构建函数的实例,用于判断具体的对象类型;
3、Object.prototype.toString 相对而言,判断类型更加残缺;
Object.prototype.toString.call(1) => '[Object Number]';
Object.prototype.toString.call(null) => '[Object Null]';
....
4、特定的api
数组:Array.isArray([])
是否是非数字:isNaN(',')

3、类型转换
1、强制转换:
Number(false) => 0;
Number('1') => 1
Number('zg') => NaN
记住转换规则:
转布尔值规定:
1、undefined null false NaN ''、0、-0都转为false;
2、其余所有值都转为true,包含所有对象;
转数字规定:
1、true为1,false为0
2、null为0,undefined为NaN,symbol报错
2、隐式转换
(比拟繁琐)
4、this
一般函数:
1、函数被谁调用,this就是谁,没有被对象调用,this就是window;
2、以下状况数优先级最高的,this只会绑定在c上,不会被任何形式批改this指向:
var c = new foo();
c.a = 3;
console.log(c.a)
3、利用call、bind、apply扭转this指向,优先级仅次于new

箭头函数:    箭头函数没有this,所以所有妄图扭转箭头函数this指向都是有效的。    箭头函数的this只取决于定义时的环境,比方如下代码中的fn箭头函数是在window环境下定义的,无论如何调用,this都指向window。    var a = 1;    const fn = () => {        console.log(this.a);    }    const obj = {        fn,        a: 2    }    obj.fn(); // 1牢记规定。比方这道题:      const a = {        b: 2,        foo: function() {            console.log(this.b);        }      }      function b(foo) {        foo();      }      b(a.foo); //undefined this => window,this.b => undefined

5、闭包

定义:如果一个函数能拜访内部的变量,那么这个函数他就是一个闭包,而不是肯定要返回一个函数。`    let a = 1; //fn是闭包     function fn() {         console.log(a)     }     function fn1() {         let a = 1;         return () => { console.log(a) }     }     const fn2 = fn1();     fn2();     详情见:[闭包](https://juejin.cn/post/6947860760840110088#heading-18)`

6、new

new操作符能够帮忙构建一个实例,并绑定到this,执行步骤如下:    1、新生成一个对象;    2、对象连接到构造函数原型上,并绑定this;    3、执行构造函数代码;    4、返回新对象;        在第四步返回新对象这边有一个状况会例外:`    function Test(name) {        this.name = name;        console.log(this); Test {name: 'yck'}        return {            age: 26        }    }        const t = new Test('yck');    console.log(t); // {age: 26}    console.log(t.name) // 'undefined'` 

7、作用域

全局;函数作用域;块级作用域;

8、原型

![image](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c5f2308aa8424e7d9bcb5dfc9fe8c58c~tplv-k3u1fbpfcp-zoom-1.image?imageslim)

上图总结出:

1、所有对象都有一个属性 __proto__ 指向一个对象,也就是原型;2、每个对象的原型都能够通过constructor找到构造函数,构造函数也能够通过prototype找到原型;3、所有函数都能够通过__proto__找到Function对象4、所有对象都能够通过__proto__找到Object对象;5、对象之间通过__proto__连接起来,这样称之为原型链。以后对象上不存在的属性能够通过原型链一层层网上查找,直到顶层Object对象,再往上就是null

9、继承

class不是其余语言里的类,实质就是一个函数;

   class Person {}   Person instanceof Function //true

ES5和ES6继承的区别:

1、ES6继承的子类须要调用super()能力拿到子类,ES5的话是通过apply这种绑定的形式2、类申明不会晋升,和let这些统一。

ES5实现继承的形式有很多种:

 function Super() {} Super.prototype.getNumber = function() {    return 1; } function Sub() {} Sub.prototype = Object.create(Super.prototype, {    constructor: {        value:Sub,        a: 2,    } }) let s = new Sub(); s.getNumber();

10、深浅拷贝

浅拷贝:两个对象第一层的援用不雷同就是浅拷贝能够通过assign、扩大运算符等形式来实现浅拷贝:    ```    let a = {         age: 1    }    let b = Object.assign({}, a);    a.age = 2;    console.log(b.age) //1    b = {...a}    a.age = 3    console.log(b.age) //2```深拷贝:两个对象外部所有的援用都不雷同    最简略的深拷贝就是应用 JSON.parse(JSON.stringify(object)),不过只反对JSON类型,也不能解决循环援用的问题   

11、Promise

1、应用all实现并行需要2、Promise.all错误处理3、手写all的实现```function promiseAll(promises) {    return new Promise( (resolve, reject) => {        if (!Array.isArray(promises)) {            return reject('arguments must be Array')        }    })        let count = 0,        newValues = new Array(promises.length);    for (let i = 0; i < promises.length;i++) {        Promise.resolve(promises[i]).then( res => {            count++;            newValues[i] = res;            if (count === newValues.length) {                return resolve(newValues)            }        }, error => reject(error))    }}```4、Promise.race() 比比谁最快,总是输入执行最快的```Promise.race([      new Promise(function(resolve, reject) {        setTimeout(() => resolve(1), 1000)      }),      new Promise(function(resolve, reject) {        setTimeout(() => resolve(2), 100)      }),      new Promise(function(resolve, reject) {        setTimeout(() => resolve(3), 10)      })    ]).then(value => {      console.log(value) // 3    })```

12、async、 await

和promise相比,劣势在于解决then的调用链,可能更清晰精确的写出代码。毛病在于滥用会导致性能问题,因为await会阻塞代码,如果之后的异步代码并不依赖于前者,但依然须要期待前者实现,导致代码失去并发性,此时更应该应用Promise.all
var a = 0var b = async () => {  a = a + await 10  console.log('step2', a) // -> 10}b()a++console.log('step1', a) // -> 1

13、事件循环

记住:js是一门单线程语言,永远只能同时执行一个工作,js中的异步就是提早执行的同步代码。Event Loop执行程序如下:1、执行同步工作2、执行完所有同步代码当前且执行栈为空,判断是否有微工作须要执行;3、执行完所有微工作且微工作队列为空4、是否有必要渲染页面5、执行一个宏工作
console.log("script start")setTimeout( () => {    console.log(setTimeout)}, 0)Promise.resolve().then( () => {    Promise.resolve().then( () => {        console.log('queueMicrotask')    })    console.log("promise")})console.log("script end")

上述代码执行过程形容:

1、遇到console.log执行并打印;2、遇到setTimeout将回调退出到宏工作3、遇到Promise.resolve(),此时状态扭转,因而then回调退出到微工作队列;4、遇到console.log执行并打印此时同步工作全副执行结束,别离打印了'script start'和'script end'。开始判是否有微工作须要执行5、微工作队列存在工作。开始执行.then()回调函数6、遇到queueMicrotask,将回调退出到微工作队列7、遇到console.log打印8、查看发现微工作队列存在工作,执行queueMicrotask回调9、遇到console.log打印此时发现微工作队列曾经清空,判断是否须要进行UI渲染10、执行宏工作,开始执行setTimeout回调11、遇到console.log执行并打印执行一个宏工作即完结,寻找是否存在微工作,开始循环判断

14、模块化

CommonJs
module.exports = {    a: 1}exports.a = 1;根本实现var module = {    exports: {}}var exports = module.exportsvar load = function(module) {    var a = 1;    module.exports = a;    return module.exports;}

CommonJs和ESM的区别是:

1、前者反对动静导入,也就是require('xx.js'),后者应用import();2、前者是同步导入,因为用于服务端,文件都在本地,同步导入即便卡住主线程影响也不大,而后者用于浏览器,须要下载文件,如果也采纳同步导入会对渲染有很大影响3、前者在导出时都是值拷贝,就算导出的值变了,导入的值也不会变,所以如果想更新值,必须从新导入一次。后者采纳实时绑定的形式,导入导出的值都指向同一个内存地址,所以导入值会追随导出值变动。

15、垃圾回收

16、手写考点

1、0.1 + 0.2 ! == 0.3;

因为JS采纳IEEE 754双精度(64位),并且只有采纳IEEE 754的语言都有该问题。存在问题的起因是浮点数用二级制示意的时候是无穷的,因为精度的问题,两个浮点数相加会造成阶段失落精度,因而再转换为十进制就出了问题。解决办法如下:export const addNum = (num1, num2) => {  let sq1, sq2, m;  try {    sq1 = num1.toString().split('.')[1].length;  } catch(e) {    sq1 = 0  }  try {    sq2 = num2.toString().split('.')[1].length;  } catch(e) {    sq2 = 0  }  m = Math.pow(10, Math.max(sq1, sq2));  return (Math.round(num1 * m) + Math.round(num2 * m)) / m}

2、防抖

简易版:const debounce = (func, wait = 200) => { let timer = 0; return function() {    if (timer) clearTimeout(timer);    timer = setTimeout( () => {        func.apply(this, args)    }, wait) }}