今天一个后端同事找我帮忙看一个后台的前端问题
问题其实很简单,就是下面这行代码并没有正常执行(就是网页没有出一个确认弹窗请求用户确认)
if (confirm('你确定要取消订单吗?') { // 取消订单 }
通过断点发现 confirm
方法被重写(Override)了
因为后台是用一个很老的 UI 框架搭建的,平时都是后端人员在维护,大部分脚本都是在 script
标签中直接写的,变量、函数全是暴露在全局作用域,加上每个后端对 JS
的了解参差不齐,所以会写出一个和全局方法同名的函数也不足为奇吧
最后当然是重命名之前定义的 confirm
函数来解决这个问题
事后,我在想,还有其他方法解决这个问题吗?
比如这么一个场景:我提供一个插件脚本给别的开发者异步载入并调用里面的方法,而这个方法刚好就要用到浏览器原生的方法
Plugins.prototype.alert = function (message) {
window.alert(message);
}
显然,如果别的开发者在我的插件载入之前就重写了 alert
事件,那这个方法就实现不了「我预期的效果」了
这时候,除了在文档中提醒调用者不用重写哪些原生方法外,还有别的方法可以「找回」原生的方法吗?
确实还有一个并不完美的方法
原理是通过插入一个 iframe
来获得一个像「新的一样」的浏览器上下文
const iframe = document.createElement('iframe');
iframe.style.display = 'none';
document.body.appendChild(iframe);
然后修改一下插件的 alert
方法
Plugins.prototype.alert = function (message) {
const iframeAlert = iframe.contentWindow.alert.bind(window);
const alert = window.alert;
const nativeAlert = alert
? alert.toString() === 'function alert() { [native code] }'
? alert
: iframeAlert
: iframeAlert;
nativeAlert(message);
}
注意要将 iframe
的方法拿过来的时候要绑定当前页面的上下文,比如 querySelector
方法就需要
querySelector = iframe.contentDocument.querySelector.bind(document);
否则,选择的是 iframe
文档的元素
如果 document.createElement
也被重写了呢?
还可以用 HTMLDocument.prototype.createElement
凑合
但是如果也这个也被重写了的话,那就没办法了,这就是为什么这个方法并不完美