17K star 仓库,解决 90% 的大厂基础面试题( 二 )

隐式转换隐式转换规则是最烦的,其实笔者也记不住那么多内容 。况且根据笔者目前收集到的最新面试题来说,这部分考题基本绝迹了,当然讲还是讲一下吧 。
对象转基本类型:

  • 调用 Symbol.toPrimitive,转成功就结束
  • 调用 valueOf,转成功就结束
  • 调用 toString,转成功就结束
  • 报错
四则运算符:
  • 只有当加法运算时,其中一方是字符串类型,就会把另一个也转为字符串类型
  • 其他运算只要其中一方是数字,那么另一方就转为数字
== 操作符
常见考点如果这部分规则记不住也不碍事,确实有点繁琐,而且考得也越来越少了,拿一道以前常考的题目看看吧:
[] == ![] // -> ?thisthis 是很多人会混淆的概念,但是其实他一点都不难,不要被那些长篇大论的文章吓住了(我其实也不知道为什么他们能写那么多字),你只需要记住几个规则就可以了 。
普通函数function foo() {console.log(this.a)}var a = 1foo()var obj = {a: 2,foo: foo}obj.foo()// 以上情况就是看函数是被谁调用,那么 `this` 就是谁,没有被对象调用,`this` 就是 `window`// 以下情况是优先级最高的,`this` 只会绑定在 `c` 上,不会被任何方式修改 `this` 指向var c = new foo()c.a = 3console.log(c.a)// 还有种就是利用 call,Apply,bind 改变 this,这个优先级仅次于 new箭头函数因为箭头函数没有 this,所以一切妄图改变箭头函数 this 指向都是无效的 。
箭头函数的 this 只取决于定义时的环境 。比如如下代码中的 fn 箭头函数是在 windows 环境下定义的,无论如何调用,this 都指向 window 。
var a = 1const fn = () => {console.log(this.a)}const obj = {fn,a: 2}obj.fn()常见考点这里一般都是考 this 的指向问题,牢记上述的几个规则就够用了,比如下面这道题:
const a = {b: 2,foo: function () { console.log(this.b) }}function b(foo) {// 输出什么?foo()}b(a.foo)闭包首先闭包正确的定义是:假如一个函数能访问外部的变量,那么这个函数它就是一个闭包,而不是一定要返回一个函数 。这个定义很重要,下面的内容需要用到 。
let a = 1// fn 是闭包function fn() {console.log(a);}function fn1() {let a = 1// 这里也是闭包return () => {console.log(a);}}const fn2 = fn1()fn2()大家都知道闭包其中一个作用是访问私有变量,就比如上述代码中的 fn2 访问到了 fn1 函数中的变量 a 。但是此时 fn1 早已销毁,我们是如何访问到变量 a 的呢?不是都说原始类型是存放在栈上的么,为什么此时却没有被销毁掉?
接下来笔者会根据浏览器的表现来重新理解关于原始类型存放位置的说法 。
先来说下数据存放的正确规则是:局部、占用空间确定的数据,一般会存放在栈中,否则就在堆中(也有例外) 。那么接下来我们可以通过 Chrome 来帮助我们验证这个说法说法 。
17K star 仓库,解决 90% 的大厂基础面试题

文章插图
 
上图中画红框的位置我们能看到一个内部的对象 [[Scopes]],其中存放着变量 a,该对象是被存放在堆上的,其中包含了闭包、全局对象等等内容,因此我们能通过闭包访问到本该销毁的变量 。
另外最开始我们对于闭包的定位是:假如一个函数能访问外部的变量,那么这个函数它就是一个闭包,因此接下来我们看看在全局下的表现是怎么样的 。
let a = 1var b = 2// fn 是闭包function fn() {console.log(a, b);}从上图我们能发现全局下声明的变量,如果是 var 的话就直接被挂到 globe 上,如果是其他关键字声明的话就被挂到 Script 上 。虽然这些内容同样还是存在 [[Scopes]],但是全局变量应该是存放在静态区域的,因为全局变量无需进行垃圾回收,等需要回收的时候整个应用都没了 。
只有在下图的场景中,原始类型才可能是被存储在栈上 。
这里为什么要说可能,是因为 JS 是门动态类型语言,一个变量声明时可以是原始类型,马上又可以赋值为对象类型,然后又回到原始类型 。这样频繁的在堆栈上切换存储位置,内部引擎是不是也会有什么优化手段,或者干脆全部都丢堆上?只有 const 声明的原始类型才一定存在栈上?当然这只是笔者的一个推测,暂时没有深究,读者可以忽略这段瞎想 。


推荐阅读