JS的一些坑

807 阅读2分钟

写在前面

最近看了一些前端的资料,也动手写了一些代码,记录并总结一下在实践的过程中遇到的一些比较诡异的JS的一些用法,希望可以帮助到大家,也提升一下自己。

正文开始

1. 获取节点

先看一段代码,思考一下结果会是什么?


<body>
    <p> 标题 </p>
</body>

<script type="text/javascript" language="javascript">
    var pNodes = document.getElementsByTagName("p")
    for (let i=0; i< pNodes.length; i++)  {
        pNode = pNodes[i]
        // 这里只是展示对应的逻辑 实际上是需要对新的节点有额外的样式补充
        const newPNode = document.createElement("p");
        // 新的节点添加到老节点之后
        pNode.parentNode.appendChild(newPNode)
    }
</script>

很不幸这段代码会使浏览器卡住,循环结束不了,下面就分析为什么以及怎么样避免。

    1. JavaScript document.getElementsByTagName("p") 返回的是节点的数组对象;
    1. JQuery $("td") JQuery的元素选择器也是返回的节点的数组对象;

需要注意的是 document.getElementsByTagName("p") 返回的是动态的DOM结构,DOM发生变化,结果也会变化;$("td")返回的是静态的,是jquery选择器方法执行时的结果。

所以在动态操纵此类数组节点时候一定要注意选择器返回的数组对象是可变的还是不可变的。

2. 兄弟节点

下面这一段代码的结果是什么?

 <body>
    <ul >
        <li id='1'>1</li>
        <li id='2'>2</li>
        <li id='3'>3</li>
    </ul>
    <script>
        l1 = document.getElementById("1")
        console.log(l1.nextSibling) 
        // #text
    </script>
 </body>

其实我们期望的结果是<li id='2'>2</li> 但是事实却是#text

解决方案是使用nextElementSibling

 <body>
    <ul >
        <li id='1'>1</li>
        <li id='2'>2</li>
        <li id='3'>3</li>
    </ul>
    <script>
        l1 = document.getElementById("1")
        console.log(l1.nextElementSibling)
    </script>
 </body>

总结:

  • nextSibling 属性返回元素节点之后的兄弟节点(包括文本节点、注释节点);
  • nextElementSibling 属性只返回元素节点之后的兄弟元素节点(不包括文本节点、注释节点);

3. 变量提升机制

思考一下 下面的代码会输出什么?

function getValue(flag) {
    console.log(value) // undefined
    if (flag) {
        var value = "hello world";
        return value
    } else {
        console.log(value) // undefined
        return null;
    }
}
getValue()

是不是答案跟想的不太一样 这是因为变量提升的机制,对于关键字var声明的变量在预编译阶段会将其提到最前面声明,类似这样

function getValue(flag) {
    var value;
    if (flag) {
        var value= "hello world";
        return value;
    } else {
        return null;
    }
}

4. 函数内部变量

继续思考一下 下面的代码会输出什么?

var name = "hello";
function setName(){
    name = "world";
}
setName();
console.log(name); 
// world
var name = "hello";
function setName(name){
    name = "world";
    console.log(name) // world
}
setName();
console.log(name); // hello

总结:对于函数内部使用变量的优先级是内部变量大于全局变量,但是对于没有声明的局部变量会使用全局变量(形参也是局部变量);在使用var定义变量的时候一定要注意使用范围,最好使用ES中的const let 去替换,减少不必要的系统问题。