01 - 数据类型
值类型(基本类型):字符串(String)、数字(Number)、布尔(Boolean)、对空(Null)、未定义(Undefined)、Symbol。
引用数据类型(对象类型):对象(Object)、数组(Array)、函数(Function),还有两个特殊的对象:正则(RegExp)和日期(Date)。
02 - 检测数据类型
type of
可以正常检测出:number、boolean、string、object、function、undefined、symbol、bigint
- 检测基本数据类型,null会检测object,因为null是一个空的引用对象
- 检测复杂数据类型,除function外,均为object
instanceof
instanceof
运算符用于检测构造函数的prototype
属性是否出现在某个实例对象的原型链上注意:只能检测复杂数据类型
toString
toString() 是 Object 的原型方法,调用该方法,默认返回当前对象的 [[Class]] 。这是一个内部属性,其格式为 [object Xxx] ,其中 Xxx 就是对象的类型。
对于 Object 对象,直接调用 toString() 就能返回 [object Object] 。而对于其他对象,则需要通过 call / apply 来调用才能返回正确的类型信息。
Object.prototype.toString.call('') ; // [object String] Object.prototype.toString.call(1) ; // [object Number]
constructor
代表获取由哪个构造函数创建而出,可以检测出字面量方式创建的对象类型,因为字面方式创建,实际由对应类创建而出 不是字面量的方式只会获取到构造函数 const dog = new Animal('大黄') console.log(dog.constructor === Object) // false console.log(dog.constructor === Animal) // true
isArray可以检测出是否为数组
03 - 作用域
通常来说,一段程序代码中所用到的名字并不总是有效和可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。
作用域的作用:
- 提高了程序逻辑的局部性。
- 增强了程序的可靠性,减少了名字冲突。
JavaScript(es6前)中的作用域有两种:
全局作用域
作用于所有代码执行的环境(整个 script 标签内部)或者一个独立的 js 文件。
- 局部作用域(函数作用域)
- JS没有块级作用域(Es6之前)
04 - 作用域链
只要是代码都在一个作用域中,写在函数内部的局部作用域,未写在任何函数内部即在全局作用域中;如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域;根据在内部函数可以访问外部函数变量的这种机制,用链式查找决定哪些数据能被内部函数访问,就称作作用域链
05 - 原型链和成员的查找机制
任何对象都有原型对象,也就是prototype属性,任何原型对象也是一个对象,该对象就有__proto__属性,这样一层一层往上找,就形成了一条链,我们称此为原型链;
当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性。 如果没有就查找它的原型(也就是 __proto__指向的 prototype 原型对象)。 如果还没有就查找原型对象的原型(Object的原型对象)。 依此类推一直找到 Object 为止(null)。 __proto__对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线。
06 - 谈谈你对 this 的理解?
this
是一个在运行时才进行绑定的引用,在不同的情况下它可能会被绑定不同的对象。
默认绑定 (指向 window 的情况) (函数调用模式 fn() )
默认情况下,this
会被绑定到全局对象上,比如在浏览器环境中就为window
对象,在 node.js 环境下为global
对象。
隐式绑定 (谁调用, this 指向谁) (方法调用模式 obj.fn() )
如果函数的调用是从对象上发起时,则该函数中的 this
会被自动隐式绑定为对象
显式绑定 (又叫做硬绑定) (上下文调用模式, 想让 this 指向谁, this 就指向谁)
硬绑定 => call apply bind
new 绑定 (构造函数模式)
另外,在使用 new
创建对象时也会进行 this
绑定
当使用 new
调用构造函数时,会创建一个新的对象并将该对象绑定到构造函数的 this
上
07 - 箭头函数中的 this 指向什么?
箭头函数不同于传统函数,它其实没有属于⾃⼰的 this
,
它所谓的 this
是, 捕获其外层 上下⽂的 this
值作为⾃⼰的 this
值。
并且由于箭头函数没有属于⾃⼰的 this
,它是不能被 new
调⽤的。
08 - 如何判断是否是数组?
方法一:使用 toString
方法
function isArray(arg) { return Object.prototype.toString.call(arg) === '[object Array]' } let arr = [1, 2, 3] isArray(arr) // true
方法二:使用 ES6 新增的 Array.isArray 方法
09 - async/await 是什么?
ES7 标准中新增的 async 函数,从目前的内部实现来说其实就是 Generator 函数的语法糖。
它基于 Promise,并与所有现存的基于 Promise 的 API 兼容。
async 关键字
async
关键字用于声明⼀个异步函数(如async function asyncTask1() {...}
)async
会⾃动将常规函数转换成 Promise,返回值也是⼀个 Promise 对象async
函数内部可以使⽤await
await 关键字
await
用于等待异步的功能执⾏完毕var result = await someAsyncCall()
await
放置在 Promise 调⽤之前,会强制 async 函数中其他代码等待,直到 Promise 完成并返回结果await
只能与 Promise ⼀起使⽤await
只能在async
函数内部使⽤
10、Promise 的理解
Promise 是一种为了避免回调地狱的异步解决方案
Promise 是一种状态: pending(进行中)、resolve(已成功)和rejected(已失败) 只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态
Promise的状态一旦改变,就不会再变,任何时候都可以得到这个结果,状态不可以逆,只能由 pending变成resolve或者由pending变成rejected
Promise 是一个构造函数
Promise 构造函数原型上的方法,可以通过创建一个 Promise 实例进行调用
- Promise.prototype.then()
- Promise.prototype.catch()
- Promise.prototype.finally()
Promise 构造函数原型上的方法,可以通过创建一个 Promise 实例进行调用
1-1、静态方法-all
Promise.all()参数可以传递一个数组,数组中记录所有的 promise 异步处理
返回值是一个 Promise 的实例对象 then 方法可以获取到所有的 promise 异步处理的结果,一旦有某一个调用执行了 reject,则终止进入 catch
1-2、静态方法-allSettled
Promise.all 和 allSettled 基本一样,区别是,then 始终可以获取到异步的状态,哪怕其中有一个失败
1-3、静态方法-race
Promise.race 使用和 all 一样,但是只返回第一个结果,不管成功或失败
1-3、静态方法-any
Promise.any 返回第一个成功的结果
11、箭头函数和普通函数的区别
箭头函数与普通函数的区别在于:
1、箭头函数没有this,所以需要通过查找作用域链来确定this的值,这就意味着如果箭头函数被非箭头函数包含,this绑定的就是最近一层非箭头函数的this,
2、箭头函数没有自己的arguments对象,但是可以访问外围函数的arguments对象
3、不能通过new关键字调用,同样也没有new.target值和原型
1、语法更加简洁、清晰
2、箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承 this。
3、箭头函数继承而来的this指向永远不变
4、.call()/.apply()/.bind()无法改变箭头函数中this的指向
5、箭头函数不能作为构造函数使用
6、箭头函数没有自己的arguments,可以在箭头函数中使用rest参数代替 arguments对象,来访问箭头函数的参数列表
7、箭头函数没有原型prototype
8、箭头函数不能用作Generator函数,不能使用yeild关键字
9、箭头函数不具有super,不具有new.target