「敲黑板」JS 类型转换及访问拦截

前言

面试的时候,你会遇到许多奇奇怪怪的问题。就好像上学的时候,你在数学课本里学习了等边三角形的三个内角都是等于 60 度,你很少能见到卷子里直接问你等边三角形的三个内角是多少度。多数情况下这个知识点会被嵌套在一个几何题里,作为一个论证依据,如果你不知道这个知识点,那就解答不出这道题。

前端面试的时候,面试官问你奇奇怪怪的问题,你可能觉得,我写业务根本用不上这些鸟东西。如果你的思想停留在这个位置,那可能你也就只能停留在切图仔这个层面。

dasfad.gif

类型转换

问:a == 1 && a == 2 && a == 3,如何让其返回 true?

看到这个问题,我一开始是不知所措的,a 若是一个常量,那么它必然某个值,为何能同时等于 3 个值。正当我百思不得其姐的时候,我再次认真的审题,a 在这条表达式中有一个动作,就是去和 123 依次做了判读是否相等,在 JS 中,两个不同类型的值在判断是否相等的时候,都会做一次转换,我们能不能控制这个转换的方法,并且返回新的值呢?我们尝试如下代码:

var a = {
  toString: function() {
    console.log('转换')
  }
}
a == 1
// 转换
// false
a == '1'
// 转换
// false
a == {}
// false
a == []
// false
复制代码

如上述代码所示,我们重写对象 atoString方法。

  • 当对象 a 和一个数字 1 做比较的时候,执行了 atoString 方法。
  • 当对象 a 和一个字符串 1 做比较的时候,执行了 atoString 方法。
  • 当对象 a 和一个空对象做比较的时候,未执行 atoString 方法。

知识点:这便是 JS 的类型转换,引用类型在和基础类型做比较的时候,会先经过 toString 方法做类型转换。

所有引用类型的隐式原型下,都有一个 toString 方法,如下图所示:

image.png

那么,上述的考题就好解决了,思路大概就是,设置 a 变量为一个对象,重写对象的 toString 方法,大致如下所示:

var a = {
  value: 0,
  toString: function() {
    return ++this.value
  }
}

a == 1 && a == 2 && a == 3
// true
复制代码

每次对比的时候,都会触发 toString 方法,返回自增后的值,依次加到 3 为止,最后返回 true

这里穿插一个小知识,上述重写 toString 不要用尖头函数,如果使用尖头函数,函数内的 this 将会指向全局 window 对象,尖头函数的 this 永远只想第一个包裹它的正常函数,逐级往上找,直到 window 全局对象。所以上述代码如果写了肩头函数,this.value 相当于 window.value,返回 undefiend

Object.defineProperty

如果我们将考题变种,问:a === 1 && a === 2 && a === 3,如何让其返回 true?

此时你心想,狗日的,什么乱七八糟的。没错,此时的你只能以不变应万变,那就是夯实自己的 JS 基础。变种考题和之前的区别在于,用了严格模式的 === ,它是不会触发类型转换调用 toString

解决上述问题。可以上 gettergetter 的作用就是当你访问变量的时候,会被拦截。如上述表达式,当执行到 a 的时候,其实就访问了 a 变量,那么我们引出 Object.defineProperty ,代码如下:

var value = 0
Object.defineProperty(window, 'a', {
  get() {
    return ++value
  }
})

a === 1 && a === 2 && a === 3 // true
复制代码

第一次对比 a === 1 此时访问了 a 变量,get 方法执行,返回 1。以此类推,最后 a3

总结

这些题目不是重点,重要的是这些题目背后所带出的 JS 知识。你可能觉得我平时业务开发基本上用不上这些知识点,但是真到了写一些上层架构的时候,这些基础知识,将会是你获取更多机会和财富的敲门砖,我不敢保证给大家出一个系列专栏,尽量保持周更吧,平时是真滴忙。

llq.gif

往期好文推荐

打通任督二脉的前端环境变量 — env 点赞数? 228

Vite 2.0 + React + Ant Design 4.0 搭建开发环境 点赞数? 385

面不面试的,你都得懂原型和原型链 点赞数? 593

Vue 3 和 Webpack 5 来了,手动搭建的知识该更新了 点赞数? 521

换一个角度分析,网页性能优化 点赞数? 200

你好,谈谈你对前端路由的理解 点赞数? 625

以前我没得选,现在我只想用 Array.prototype.reduce 点赞数? 588

无处不在的发布订阅模式 —— 这次一定 点赞数? 164

聊聊 JSX 和虚拟 DOM 点赞数? 110

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享