一个较冷门的JS知识
2023 年 2 月 19 日 - 00:45:13 发布
1.6K 字
6分钟
本作品采用
CC BY-NC-SA 4.0
进行许可。
本文距离首次发布已经过去了 638
天,请注意文章的时效性!
一个较冷门的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')
答案:
- window,与前文情况一样,相当于把函数提取出来作为单独变量,由全局去调用
- window,这个部分相当于在闭包内直接调用,虽然在第一层中改变了 this 指向,但是后续又是直接通过括号调用,相当于 this 还是指向全局,没有变化
- ‘hi’,箭头函数的 this 由上下文决定,而不是通过调用者决定,而之前通过 call 方法绑定了 this,所以函数内 this 指向字符串 ‘hi’
个人信息
Shiinafan
文章
43
标签
53
归档
4