为何将函数名当作对象使用?修改后函数转为构造函数的原因
Element.scrollHeight学习中的两个问题 我在学习Element.scrollHeight时遇到两个无法理解的问题,先贴出相关原代码:
function checkReading () { if (checkReading.read) { return; } checkReading.read = this.scrollHeight - Math.round(this.scrollTop) === this.clientHeight; document.registration.accept.disabled = document.getElementById("nextstep").disabled = !checkReading.read; checkReading.noticeBox.textContent = checkReading.read ? "Thank you." : "Please, scroll and read the following text."; } onload = () => { const oToBeRead = document.getElementById("rules"); checkReading.noticeBox = document.createElement("span"); document.registration.accept.checked = false; checkReading.noticeBox.id = "notice"; oToBeRead.parentNode.insertBefore(checkReading.noticeBox, oToBeRead); oToBeRead.parentNode.insertBefore(document.createElement("br"), oToBeRead); oToBeRead.onscroll = checkReading; checkReading.call(oToBeRead); }
问题列表
- 为什么要将
checkReading(函数名)当作对象/变量来使用? - 我尝试移除
checkReading相关引用,改用oToBeRead对象作为this,编写了this.read = this.scrollHeight - Math.round(this.scrollTop) === this.clientHeight这段代码后,checkReading函数被识别为构造函数,这是为什么?
以下是我修改后的代码:
function checkReading () { if (checkReading.read) { return; } this.read = this.scrollHeight - Math.round(this.scrollTop) === this.clientHeight; document.registration.accept.disabled = document.getElementById("nextstep").disabled = !this.read; this.noticeBox.textContent = checkReading.read ? "Thank you." : "Please, scroll and read the following text."; } onload = () => { const oToBeRead = document.getElementById("rules"); oToBeRead.noticeBox = document.createElement("span"); document.registration.accept.checked = false; oToBeRead.noticeBox.id = "notice"; oToBeRead.parentNode.insertBefore(checkReading.noticeBox, oToBeRead); oToBeRead.parentNode.insertBefore(document.createElement("br"), oToBeRead); oToBeRead.onscroll = checkReading; checkReading.call(oToBeRead); }

该图片显示函数被转换为构造函数,Quokka工具提示将其修改为类声明。
问题解答
为什么把
checkReading当作对象使用?
在JavaScript里,函数本身就是Function类型的对象,天然支持添加自定义属性。原代码里这么做,是把函数checkReading当成了一个小型的命名空间——用它来存储全局状态(read标记用户是否读完内容)和DOM元素(noticeBox提示框),这样可以避免声明额外的全局变量,减少全局作用域的污染,同时让相关的状态和逻辑集中在一起,更易维护。为什么修改后函数被识别为构造函数?
Quokka这类工具是通过静态代码分析来判断代码意图的:当函数内部出现this.xxx = ...这样的属性赋值操作时,工具会默认认为你可能是想把这个函数当作构造函数(也就是用new关键字调用、创建实例的函数),所以会提示你改成类声明。但实际上你是通过checkReading.call(oToBeRead)把this绑定到了DOM元素oToBeRead上,属于显式指定上下文,只是工具的静态分析没识别到这一点,产生了误判。
另外注意你修改后的代码存在逻辑错误:比如oToBeRead.parentNode.insertBefore(checkReading.noticeBox, oToBeRead)这里,你已经把noticeBox挂到了oToBeRead上,应该改成oToBeRead.noticeBox;还有this.noticeBox.textContent = checkReading.read ? ...里的checkReading.read也应该改成this.read,否则会读取错误的状态值。
内容的提问来源于stack exchange,提问作者ManojKS091

