前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >WEB开发面面谈之(5)——写JS时必须注意的的一些问题

WEB开发面面谈之(5)——写JS时必须注意的的一些问题

作者头像
张炳
发布2019-08-05 15:23:54
1.7K0
发布2019-08-05 15:23:54
举报
文章被收录于专栏:web全栈工程师的取经之路

获取body元素

非标准做法

代码语言:javascript
复制
document.body

W3C规范方法

代码语言:javascript
复制
document.getElementsByTagName('body').item(0)

使用jQuery/Zepto

代码语言:javascript
复制
$('body');

获取窗口标题

非标准做法

代码语言:javascript
复制
document.title

W3C规范方法

代码语言:javascript
复制
document.getElementsByTagName('title').item(0).innerHTML  

使用jQuery/Zepto

代码语言:javascript
复制
$('title').text()

监听iframe的加载完成事件

  • 写法1:
代码语言:javascript
复制
iframe.onload = function() {...}

问题:存在兼容性问题,IE6、7无效

  • 写法2:
代码语言:javascript
复制
iframe.onload = iframe.onreadystatechange = function(){...}

问题:逻辑复杂,事件绑定逻辑混乱,在某些浏览器上onload和onreadystatechange都会触发,需要另外加标记位判断,逻辑复杂。

  • 简洁而完全兼容的写法:
代码语言:javascript
复制
var bindIframeOnloadEvent = function(el, onload) {
 if (el.attachEvent){
    el.attachEvent("onload", onload);
 } else {
   el.onload = onload;
 }
};
bindIframeOnloadEvent(iframe, function(){...}); 

如何操作iframe内部的window

  • 写法1:
代码语言:javascript
复制
iframe.contentWindow

问题: 部分浏览器不兼容(IE67),获取失败

  • 写法2:
代码语言:javascript
复制
document.frames[frameId]

问题: 非标准调用,兼容性是问题,强制必须为iframe添加ID。

  • 简洁而完全兼容的写法:
代码语言:javascript
复制
var getIframeWindow = function(el) {
return el.contentWindow || el.contentDocument.parentWindow;
};
var win = getIframeWindow(iframe);

设置iframe的边框

  • 写法1:
代码语言:javascript
复制
iframe.boder = 0;

问题: 非W3C标准,后面很可能废弃,部分浏览器不一定支持

  • 写法2:
代码语言:javascript
复制
iframe.style.boder = 'none'; 

问题: 完全依赖CSS控制,但存在兼容性问题,IE继续头疼

  • 最终解决方案:
代码语言:javascript
复制
iframe.boder = 0;
iframe.style.boder = 'none';

如何在a标签上绑定鼠标点击事件

  • 写法1:
代码语言:javascript
复制
<a href="javascript:func();">test</a>

问题:

  1. 不符合CSP规范
  2. 等价于全局eval。只能调用公开的全局方法,污染全局变量
  3. 鼠标悬停时,状态栏会显示要运行的代码?!这对最终用户不友好
  4. 运行代码的上下文是window对象,和事件处理模型相违背
  • 写法2:
代码语言:javascript
复制
<a href="#" onclick="func();">test</a>

问题:

  1. 不符合CSP规范
  2. onclick和href在部分浏览器(IE继续躺枪)行文诡异,执行冲突异常
  3. 等价于全局eval。只能调用公开的全局方法,污染全局变量(原因同写法1)
  • 写法3:
代码语言:javascript
复制
<a href="#" onclick="func();return false;">test</a>

问题:只解决了问题2,其余问题仍存在

  • 标准写法:
代码语言:javascript
复制
<a id='aTest'>test</a>
<script>
document.getElementById('aTest').onclick = function() {
func();
};
</script>

使用jQuery/Zepto亦可,存在唯一的小问题是鼠标指针不是手形,是默认。可采用CSS样式来解决cursor:pointer 。

script标签的书写方法深挖

要点

  1. script标签的type属性不是必须的,默认缺省就是text/javascript
  2. script标签的language属性完全无用(asp时代微软似乎使用该属性来标记服务端语言是vb还是c#),不要画蛇添足
  3. 动态创建的script标签必须要指定type='text/javascript',否则JS不会执行
代码语言:javascript
复制
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = '###';
document.getElementsByTagName('body').item(0).appendChild(script);
  1. 动态创建的script追加动作是异步的,并不会立刻取得script运行结果,如果要等待加载完成需要监听完成事件
  2. 使用非标准或者比较新的属性需要格外注意,不要使代码逻辑依赖于这些特性。如defer/async属性
  3. 使用script.onerror来监听脚本执行失败的情况(语法错误,初始化运行时错误等都会触发)
  4. 监听script的完成事件比较复杂。
代码语言:javascript
复制
varbindScriptOnloadEvent = function(script, onload) {
    var done = false;
    script.onload = script.onreadystatechange = function() {
    if (!done && (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete')) {
        done = true;
        script.onload = script.onreadystatechange = null;
        onload();
        }
    };
};
bindScriptOnloadEvent(script, function(){...});

需要考虑兼容性,所以代码较多

substr函数不要使用

原因:非标准,在部分浏览器报错,甚至连我的Android4.0上的浏览器都不认该函数

替代方案:使用substring函数。

jQuery/Zepto选择器的.text()和.html()方法

现状:大多数开发同学会混淆两者并乱用,不清楚何时用哪个

详解:.text()方法用于获取和设置文本内容,.html()方法用户获取和设置HTML内容,当要设置或获取的内容仅仅为文本时,两者行为完全相同,但要操作的文本内容是HTML时,行为有着本质区别。

总结:

  1. 根据实际需要选择使用哪个方法,如能断定内容为纯文本请使用text()方法。仅当确实需要渲染HTML时才用html()方法
  2. 从安全角度,text()方法比html()方法更安全,无注入风险。
  3. 严格意义上,html()方法不符合CSP规范,直接将字符串解析为DOM节点
  4. 业务需要确实要使用.html()方法渲染动态内容时,必须做安全检查,避免恶意代码注入
  5. .text()和.html()获取值可能存在代码缩进(空格和TAB),如有需要可以使用$.trim()来剔除

数组与对象深挖

要点:

  • 数组对象仅有concat/reverse/slice/splice为标准API,而且绝对完全兼容
  • 数组对象请勿使用indexOf、lastIndexOf、map、every、forEach等非标准API,不仅兼容性存在问题,而且效率不一定高,反而不如自己实现
  • 遍历数组请将.length缓存到变量
代码语言:javascript
复制
for(vari=0,l=arr.length;i<l;i++){...}
  • 遍历数组请勿使用此写法
代码语言:javascript
复制
for(vari in arr){...}
  • 遍历key-value型对象必须使用hasOwnProperty()来过滤遍历结果。
代码语言:javascript
复制
for(var key in obj) {
if(!obj.hasOwnProperty(key) continue;
    //...
}
  • 不论是数组或对象,在遍历操作时不要改变被遍历的变量结构,如增删元素,增删key值等(虽然你可以这么做),对于元素自身及子成员的修改是绝对安全的。

关于Prototype的使用

要点:

  • 不要乱用Prototype。不要轻易在Object/Array/Function等对象上追加prototype(虽然我们已有某些库这么做了)容易产生歧义冲突,在使用for~in遍历时很容易引发问题。
  • 自定义的prototype成员会在for~in循环中出现,请根据实际情况使用hasOwnProperty()来过滤遍历结果。

不严谨的写法:

代码语言:javascript
复制
function Test() {}
Test.prototype.a = 1;
Test.prototype.b = 2;
var o = new Test();
for(vari in o) {
console.log({key: i, value: o});
}
//{key:a, value:1}
//{key:b, value:2}
严谨的写法:
var o = new Test();
for(vari in o) {
if(!o.hasOwnProperty(i)) continue;
console.log({key: i, value: o});
}
//无输出 
  • 对象的__proto成员,用途是获取当前实例的原型对象。非标准实现,存在兼容性问题,请不要使用
  • 原则上不要轻易重写已存在的prototype方法。但可以在单个实例中覆写该方法
  • prototype上定义静态对象变量,会造成所有对象共用,而不是分别创建实例,请在构造方法中分配实例

错误写法:

代码语言:javascript
复制
function Test() {}
Test.prototype.arr = [];
var a = new Test();
var b = new Test();
a.arr.push(1);
b.arr.push(2);
console.log(a.arr, b.arr);
//[1,2], [1,2]
正确写法
function Test() {
this.arr = [];
}

var a = new Test();
var b = new Test();
a.arr.push(1);
b.arr.push(2);
console.log(a.arr, b.arr);
//[1], [2]

总结

JS是门灵活的语言,灵活到想怎么写都可以。但里面坑还是不少的。在有多种选择时,多考虑下哪种方法更好,而不是盲目选择一种。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 获取body元素
  • 获取窗口标题
  • 监听iframe的加载完成事件
  • 如何操作iframe内部的window
  • 设置iframe的边框
  • 如何在a标签上绑定鼠标点击事件
  • script标签的书写方法深挖
  • substr函数不要使用
  • jQuery/Zepto选择器的.text()和.html()方法
  • 数组与对象深挖
  • 关于Prototype的使用
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档