一个较冷门的JS知识 - Shiina's Blog

一个较冷门的JS知识

2023 年 2 月 19 日 - 00:45:13 发布
1.6K 字 6分钟
本作品采用 CC BY-NC-SA 4.0 进行许可。
本文距离首次发布已经过去了 501 天,请注意文章的时效性!

一个较冷门的JS知识

前几天有群u无聊在研究b站js逆向解析,后面偶然发现b站是保留了ip归属地显示的功能,后面还发现了评论的隐藏属性

花了一个晚上成功做了个解析,是基于 header editor 去做的

GitHub:https://github.com/LightQuanta/BilibiliEnhance

后面有一天这位佬突然跑来问我说js混淆文件中这种代码的作用:

(0, z.Fl)((function () { return !1 }))

后面那一部分比较好理解,一个匿名函数被括号包起来作为一个值返回,前面就有点迷了

从头一点点看:

(0, z.Fl)

被括号包起来了,这证明他是表达式,使用逗号间隔代表按顺序解析变量,也就是这段代码会返回最后一个值

因此就明白了:

z.Fl 本身是一个函数,后面在跟上那个表达式是作为函数参数传入给 z.Fl

现在的问题是为什么要这么写:(0, z.Fl),直接写 z.Fl 不行吗

百度上搜了一下,有了结果:https://blog.csdn.net/qq_39446719/article/details/103838706

大概总结一下就是这种写法会强制改变函数的 this 指向,因为其本质相当于把对象里的函数作为一个值单独返回出来,而不是通过对象去调用这个函数:

const z = {
  Fl: function() {
    console.log(this)
  }
}

z.Fl() // obj: z
(0, z.Fl)() // Browser: window, Node: global

上面的代码等价于:

const z = {
  Fl: function() {
    console.log(this)
  }
}
z.Fl() // obj: z

// 假设使用一个临时变量存储 `(0, z.Fl)` 的返回值
const _temp = (0, z.Fl) // [Function Fl]
_temp() // 由全局对象去调用,就不是通过 z 去调用了,所以改变了指向

虽然这种写法挺离谱的,但是在各种打包工具的loader中还不少见

不推荐实际开发中用这种反人类语法,为了保障自身安全不被同事打死,写可读性高的代码,请从你他做起

接下来再出几个类似的逆天代码,读者可以想一想输出结果是什么:

const z = {
  fn: () => {
    console.log(this)
  }
}
(0, z.fn)() // 1

(function () {
  const z = {
    c() { console.log(this) }
    d: () => { console.log(this) }
  }

  (0, z.c)(); // 2
  (0, z.d)(); // 3
}).call('hi')

答案:

  1. window,与前文情况一样,相当于把函数提取出来作为单独变量,由全局去调用
  2. window,这个部分相当于在闭包内直接调用,虽然在第一层中改变了 this 指向,但是后续又是直接通过括号调用,相当于 this 还是指向全局,没有变化
  3. ‘hi’,箭头函数的 this 由上下文决定,而不是通过调用者决定,而之前通过 call 方法绑定了 this,所以函数内 this 指向字符串 ‘hi’
个人信息
avatar
Shiinafan
文章
41
标签
52
归档
4
导航