JS数据类型

  基础类型:undefinedNullBooleanStringNumberSymbolBigInt。(存储在栈内存)

  引用类型:ArrayFunctionObjectRegExpDateMath。(存储在堆内存)

JS类型检测

  typeof 基础类型正常检测(除了null),引用类型返回'object'(除了function)

  instanceof:基础类型不能检测,引用类型可以正常检测。

  Object.prototype.toString.call(): 基础和引用类型都能检查,返回 "[object Xxxx]"

JS浅拷贝

  object.assign(target,...sources);

  let cloneObj = {...obj};

  [].concat();

  arr.slice();

  assign和扩展运算缺点:1不能拷贝对象的继承属性。2、不能拷贝对象的不可枚举属性3、可以拷贝 Symbol 属性。

JS深拷贝

  1、SON.parse(JSON.stringify(x))

  缺点: 函数、undefinedSymbol 序列化会消失;

     Date 会变成字符串;

     RegExp 会变成空对象;

     NaNInfinity-Infinity会变成null

     不能拷贝'不可枚举的属性'

     不能拷贝'对象的原型链'

     不能拷贝'对象的循环引用'

  2、递归for in 遍历参数,typeof是引用类型递归,否则直接赋值)

  缺点: 不能拷贝'不可枚举的数据''Symbol类型'。;

     不能正确拷贝 ArrayDateRegExpErrorFunction 的引用类型;

     不能拷贝'对象的循环引用'

  3、改进递归

    1、不可枚举的属性 及 Symbol类型。可以使用Reflect.ownKeys 方法;

    2、判断参数是 DateRegExp 类型,则直接生成一个新的实例返回;

    3、利用 Object.getOwnPropertyDescriptors() 获得对象的所有属性 以及 对应的特性,结合Object.create() 创建一个新的对象,并继承传入原对象的原型链;

    4、利用 WeakMap 类型作为 Hash 表,因为 WeakMap 是弱引用类型,可以防止内存泄漏,作为检测循环引用很有帮组,如果循环引用则返回 WeakMap 存储的值。

   JavaScript 核心原理精讲_作用域

 

 

 

JS继承

  原型链继承

    Child.prototype = new Patent()

    缺点:原型属性共享问题。

  构造函数继承

    Function Child() { Parent.call(this) }

    缺点:不能继承父类原型上的属性和方法

  组合式继承

    原型和构造函数结合

    缺点:父类多构造一次

  原型式继承

    Object.create(parent)

    缺点:多实例中的引用类型属性指向相同的内存

  寄生式继承

    借助方法添加属性和方法。

    Object.create('用作新对象原型的对象','新对象定义额外属性的对象')。

    Let clone = Object.create(original);clone.fun = function(){...};return clone;

    缺点:多实例中引用数据类型属性指向相同的内存

  寄生组合继承

    将parentChild传入clone方法中。减少一次构造的过程。

    Child.prototype = Object.create(parent.prototype);Child.prototype = Child;

  继承中最优的方案

    Es6 extends继承

    使用babel-loader 编译可以看出也是用的寄生组合继承。

JS  newapplybindcall

  JavaScript 核心原理精讲_引用类型_02

  new 大致分为以下步骤:

  1. 创建一个新对象;
  2. 将构造函数的作用域赋给新对象(this指向新对象);
  3. 执行构造函数中的代码(为这个对象添加属性);
  4. 返回新对象。
    使用场景:

  (1) 判断数据类型。

    Object.prototype.toString.call([]).replace(/^\[object (\S+)\]$/, '$1')

  (2) 类数组借用方法。
    Array.prototype.push.call({0:'java',1:'script',length:2},'jack','lily')//{0:'java',1:'script',2:'jack',3:'lily',length:4}

  (3) 获取最大/最小值。
    Math.max.apply(Math,[13,6,10,11,16]);// 16
    Math.min.apply(Math,[13,6,10,11,16]);// 6

  (4) 继承
    function child(){ parent.call(this) }
    child.prototype = new parent();
    child.prototype.constructor = child;

JS 闭包

  全局作用域

    挂在window对象下的变量;未定义直接赋值的变量是全局变量。

    缺点:容易引起‘变量命名的冲突’。

  函数作用域

    函数中定义,在函数内部才能访问到它;函数被执行完,这个局部变量会被销毁。

  块级作用域

    使用let关键字,有‘暂时性死区’特点,定义之前不能被使用。

 

  闭包

    红宝书:闭包是指有权访问另外一个函数作用域中的变量的函数

    闭包产生的本质就是:当前环境中存在指向父级作用域的引用

    表现形式:1.返回一个函数;2.定时器、事件监听、Ajax请求;3.作为函数参数传递的形式;4.IIFE(立即执行函数)。

    解决循环输出问题:1.利用IIFE2.使用 ES6 中的 let3.定时器传入第三个参数。

JS 数组

  *构造器

    Array();字面量;Array.of()Array.from()

  *类型判断

    [] instanceof Array;

    [].constructor === Array;

    Array.prototype.isPrototypeOf([]);

    Object.getPrototypeOf([]) === Array.prototype;

    Object.prototype.toString.apply([]) === [object Array]

    Array.isArray([])

  *改变自身的方法

    poppushshiftunshiftreversesortspliceES6 copyWithinfill

  *不改变自身的方法

    concatjoinslicetoStringtoLocaleStringindexOflastIndexOf、为形成标准的toSource,以及ES7 includes

  *遍历的方法

    forEacheverysomefiltermapreducereduceRightES 中的 entriesfindfindIndexkeysvalues

 

JS 类数组

  *arguments

    Object.prototype.toString.call(arguments); // [object Arguments]

    callee 属性:被调用函数

  *HTML Collection

    它是HTML DOM 对象的一个接口,返回包含了获取到的 DOM 元素集合,返回的类型是类数组对象。它是及时更新的,当文档中的DOM变化,它会随之变化。
    Object.prototype.toString.call(document.forms[0]); // [object HTMLFormElement]

  *NodeList

    节点集合,由 querySelector 返回的。可以使用 for...of 来迭代。它是实时集合,文档中的节点树发生变化,NodeList 也随之变化。

    var list = document.querySelectorAll(input[type=checkbox]);

    Object.prototype.toString.call(list); // [object NodeList]

  *应用场景

    遍历参数操作

    定义链接字符串函数

      Array.prototype.slice.call(arguments,1).join(separa);

      myConcat(,,red,blue,orange);

    传递参数使用

      bar.apply(this,arguments);

  *类数组转换为数组

    Array.prototype.push.call(arrayLike,jack,lily);

    Array.prototype.slice.call(arguments);

    Array.prototype.concat.apply([],argument);

    Array.from(arguments);

    [...arguments];

JS数组扁平化

 JavaScript 核心原理精讲_数组_03

 

 

JS 数组排序

  冒泡排序

    两个循环,比较两个元素,调换顺序。

  快速排序

    基线,递归,合并。

  插入排序

    数组本身进行调整。首先循环遍历 i = 0开始,当前值比前面值大,进行交换。

  选择排序

  归并排序

JS sort实现

  先将元素转换为字符串,然后再进行排序。

  arr.sort([compareFunction]) compareFunction用来执行按某种顺序进行排列的函数,不写元素按照转换为字符串的各个字符的 Unicode 位点进行排序。

  sort 会根据元素个数是 n 分情况排序:

    1.当 n <= 10 时,采用插入排序;

    2.当 n > 10 时,采用三路快速排序;

    3.当 10 < n <= 1000 时,采用中位数最为哨兵元素;

    4.当 n > 1000 时,每隔 200 ~ 215 个元素挑出一个元素,放到一个新数组中,然后对他排序,找到中间位置的数,以此作为中位数。

  当 n 足够小的时候,插入排序的时间复杂度 O(n) 要优于快速排序的 O(nlogn)。因此数据量小的时候会采用插入排序

 

JS 异步编程方案

  *回调函数

    问题:回调地狱

  *Promise

    优点:可以将异步操作以同步操作的流程表达出来,避免层层嵌套的回调函数。

    缺点:使用 Promise 链式调用过多,其根本上没有解决回调地狱,依然难以维护。不过Promise 提供了 all 方法。

    一个 Promise 有三种状态:pending、fulfilled 和 rejected。

  *Generator

    特点:交出函数的执行权,需要暂停的方法可以用 yield 标注,返回的是迭代器。

    使用 * 来标注它是Generator 函数,next()依次调用,最后返回”{value:undefined,done:true}”的结果,标识该Generator 函数已经执行完毕。

  *async/await

    ES7提供新的一步方案:async/await。Async 是 Generator 函数的语法糖;写起来使得 JS 的异步代码像同步。

 

JS 代码是如何被浏览器引擎编译、执行的?

通过V8引擎,先把js代码转化成AST,然后通过解释器将AST转成字码节,在通过编译器将字码节转成机器码,最后在进行垃圾回收, 至此整个js就的执行就完成了。