# JS基础

# 说说JavaScript中的数据类型有哪些,他们在存储上的差别是什么?

分为基础类型和引用类型:

  • 基础类型:undefined、null、布尔值(Boolean)、字符串(String)、数值(Number)、symbol(es6新增)
  • 引用类型:对象(Object)、数组、Function

基础类型存储在栈内存中,引用类型存储在堆内存中

# 深拷贝浅拷贝的区别?如何实现一个深拷贝?

# 深浅拷贝的区别

浅拷贝是拷贝一层,属性为对象时,浅拷贝是复制,两个对象指向同一个地址 深拷贝是递归拷贝深层次,属性为对象时,深拷贝是新开栈,两个对象指向不同的地址

# 浅拷贝的现象有

  • Object.assign
  • Array.prototype.slice(), Array.prototype.concat()
  • 使用拓展运算符实现的复制

# 深拷贝

深拷贝开辟一个新的栈,两个对象属完成相同,但是对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性

  • 实现
    • _.cloneDeep()
    • jQuery.extend()
    • JSON.stringify() 但是这种方式存在弊端,会忽略undefined、symbol和函数
    • 手写循环递归

# == 和 ===区别,分别在什么情况使用

  • 等于操作符(==)在比较中会先进行类型转换,再确定操作数是否相等
  • 全等操作符由 3 个等于号( === )表示,只有两个操作数在不转换的前提下相等才返回 true。即类型相同,值也需相同
  • null 和 undefined 比较,相等操作符(==)为true,全等为false

除了在比较对象属性为null或者undefined的情况下,我们可以使用相等操作符(==),其他情况建议一律使用全等操作符(===)

# 谈谈this对象的理解

this 关键字是函数运行时自动生成的一个内部对象,只能在函数内部使用,总指向调用它的对象

# 绑定规则

  • 默认绑定
    • 严格模式下,不能将全局对象用于默认绑定,this会绑定到undefined,只有函数运行在非严格模式下,默认绑定才能绑定到全局对象
  • 隐式绑定
    • 函数还可以作为某个对象的方法调用,这时this就指这个上级对象
    • 函数中包含多个对象,尽管这个函数是被最外层的对象所调用,this指向的也只是它上一级的对象
  • new绑定
    • new关键字生成一个实例对象,此时this指向这个实例对象
    • 执行new操作符,其实JS内部完成了以下事情:
      • 创建一个空的简单JavaScript对象(即{});
      • 将构造函数的prototype绑定为新对象的原型对象 ;
      • 将步骤1新创建的对象作为this的上下文并执行函数 ;
      • 如果该函数没有返回对象,则返回this。
  • 显示绑定
    • apply()、call()、bind()是函数的一个方法,作用是改变函数的调用对象。
    • 它的第一个参数就表示改变后的调用这个函数的对象。因此,这时this指的就是这第一个参数

# 箭头函数

  • 在代码书写时就能确定 this 的指向(编译时绑定)
  • 箭头函数在自己的作用域内不绑定 this,即没有自己的 this,如果要使用 this ,就会指向定义时所在的作用域的 this 值

# 优先级

  • new绑定优先级 > 显示绑定优先级 > 隐式绑定优先级 > 默认绑定优先级

# JavaScript中执行上下文和执行栈是什么?

执行上下文是一种对Javascript代码执行环境的抽象概念,也就是说只要有Javascript代码运行,那么它就一定是运行在执行上下文中

# 类型分为三种

  • 全局执行上下文:只有一个,浏览器中的全局对象就是 window对象,this 指向这个全局对象
  • 函数执行上下文:存在无数个,只有在函数被调用的时候才会被创建,每次调用函数都会创建一个新的执行上下文
    • 每次调用函数创建一个新的上下文,会创建一个私有作用域,函数内部声明的任何变量都不能在当前函数作用域外部直接访问
  • Eval 函数执行上下文: 指的是运行在 eval 函数中的代码,很少用而且不建议使用

# 执行栈

执行栈,也叫调用栈,具有 LIFO(后进先出)结构,用于存储在代码执行期间创建的所有执行上下文

# 流程

  • 当Javascript引擎开始执行你第一行脚本代码的时候,它就会创建一个全局执行上下文然后将它压到执行栈中
  • 每当引擎碰到一个函数的时候,它就会创建一个函数执行上下文,然后将这个执行上下文压到执行栈中
  • 引擎会执行位于执行栈栈顶的执行上下文(一般是函数执行上下文),当该函数执行结束后,对应的执行上下文就会被弹出,然后控制流程到达执行栈的下一个执行上下文

# typeof 与 instanceof 区别

  • typeof会返回一个变量的基本类型,instanceof返回的是一个布尔值
  • instanceof 可以准确地判断复杂引用数据类型,但是不能正确判断基础数据类型
  • 而typeof 也存在弊端,它虽然可以判断基础数据类型(null 除外),但是引用数据类型中,除了function 类型以外,其他的也无法判断

可以看到,上述两种方法都有弊端,并不能满足所有场景的需求

如果需要通用检测数据类型,可以采用Object.prototype.toString,调用该方法,统一返回格式“[object Xxx]”的字符串

# bind、call、apply 区别?如何实现一个bind?

  • 三者都可以改变函数的this对象指向
  • 三者第一个参数都是this要指向的对象,如果如果没有这个参数或参数为undefined或null,则默认指向全局window
  • 三者都可以传参,但是apply是数组,而call是参数列表,且apply和call是一次性传入参数,而bind可以分为多次传入
  • bind是返回绑定this之后的函数,apply、call 则是立即执行

# ajax原理是什么?如何实现?

AJAX全称(Async Javascript and XML)即异步的JavaScript 和XML 是一种创建交互式网页应用的网页开发技术,可以在不重新加载整个网页的情况下,与服务器交换数据,并且更新部分网页

# Ajax的原理

简单来说通过XmlHttpRequest对象来向服务器发异步请求,从服务器获得数据,然后用JavaScript来操作DOM而更新页面

  • 实现 Ajax异步交互需要服务器逻辑进行配合,需要完成以下步骤:
    • 创建 Ajax的核心对象 XMLHttpRequest对象
    • 通过 XMLHttpRequest 对象的 open() 方法与服务端建立连接
    • 构建请求所需的数据内容,并通过XMLHttpRequest 对象的 send() 方法发送给服务器端
    • 通过 XMLHttpRequest 对象提供的 onreadystatechange 事件监听服务器端你的通信状态
    • 接受并处理服务端向客户端响应的数据结果
    • 将处理结果更新到 HTML页面中