JavaScript系列(一):相关概念

冒泡事件

“冒泡”这个词就能想到肯定是从底部往上升,而冒泡事件就是在第一层定义的事件,在顶层也会被触发。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>qita</title>
    <script>
//        'use strict'
        function cli() {
            alert('触发事件')
        }

        window.onload = function () {
            document.getElementById('div1').addEventListener('click', cli)
            document.getElementById('div2').addEventListener('click', cli)
            document.getElementById('div3').addEventListener('click', cli)
            document.getElementById('p1').addEventListener('click', cli)
        }
    </script>
</head>
<body>
<div id="div1">
    div1
    <div id="div2">
        div2
        <div id="div3">
            div3
            <p id="p1">p1</p>
        </div>
    </div>
</div>
</body>
</html>

此时,当我们点击最内层的p1时,外层的每个事件也都会被触发。

冒泡事件的三个阶段

捕获阶段:事件从跟节点流向目标节点,途中流经各个DOM节点,在各个节点上触发捕获事件,直到到达目标节点。此阶段作用是为了建立传播路径,为冒泡阶段铺路。
目标阶段:事件到达目标节点时,就到了目标阶段,事件会在该阶段触发。
冒泡阶段:事件触发后不会停止,会根据捕获阶段留下的路一层层触发。

MDN上的解释:

  • 捕获阶段:

    1. 浏览器会检查最外层的祖先html,是否在捕获阶段注册了onclick事件,如果是,则执行它。
    2. 接着,移动到html中的下一个元素,并执行第一步,依次往后推,直到达到被点击的元素为止。
  • 冒泡阶段

    1. 浏览器先检查被点击的对象是否注册了onclick事件,如果是,则执行它。
    2. 然后移动到它下一个最直接的父元素,然后执行相同的操作,依次往后推,直到html元素。

事件委托

冒泡还允许我们利用事件委托——这个概念依赖于这样一个事实,如果你想要在大量子元素中单击任何一个都可以运行一段代码,您可以将事件监听器设置在其父节点上,并将事件监听器气泡的影响设置为每个子节点,而不是每个子节点单独设置事件监听器。

一个很好的例子是一系列列表项,如果你想让每个列表点击时弹出一条信息,您可以将click单击事件监听器设置在父元素<ul>上,它将会冒泡到列表项上。

终止冒泡事件的两个方法


function cli(event) {
    alert('触发事件')
    /* 以上面代码为基础,添加一行,此方法就是终止事件冒泡 */
    event.stopPropagation();
}
window.onload = function () {
    document.getElementById('div1').addEventListener('click', cli)
    document.getElementById('div2').addEventListener('click', cli)
    document.getElementById('div3').addEventListener('click', cli)
    document.getElementById('p1').addEventListener('click', cli)
}
function cli(event) {
    /* 如果事件的触发者 == 事件的绑定者 */
    if (event.target == event.currentTarget) alert('触发事件')
}
window.onload = function () {
    document.getElementById('div1').addEventListener('click', cli)
    document.getElementById('div2').addEventListener('click', cli)
    document.getElementById('div3').addEventListener('click', cli)
    document.getElementById('p1').addEventListener('click', cli)
}

补充

根据上面所述,事件传递一般分两种,冒泡传递捕获传递,一个是自上(内)而下(外),一个是自下(外)而上(内)。详情请见:菜鸟教程-冒泡事件

变量提升

在作用域底部定义的函数或者变量会被上升到作用域的顶部。函数或变量都可以先使用后声明,使用和声明不分先后顺序,但是前提是后声明变量时不能初始化。而且let类型是不存在变量提升的概念,同时还带来一个概念叫“暂时性死区”,被let装饰的类型变量必须先声明后使用,不然一切都是错。

window.onload = function () {
    console.log(a) // undefined
    var a;

    console.log(bar); // 报错ReferenceError
    let bar = 2;
}

严格模式

放弃变量提升除了let之外还有一个语法(又或者叫严格模式),在 JavaScript 1.8.5 (ECMAScript5) 中新增,严格模式通过在脚本或函数的头部添加 "use strict"; 表达式来声明。

为什么使用严格模式

  • 消除代码运行的一些不安全之处,保证代码运行的安全;
  • 为未来新版本的Javascript做好铺垫。
  • 提高编译器效率,增加运行速度;

严格模式的限制

  • 不允许使用未定义的变量
  • 显式报错
  • 不允许删除变量、对象、函数
  • 不允许变量重名
  • 不允许使用八进制
  • 不允许使用转义字符
  • 不允许对只读属性赋值
  • 不允许对一个使用getter方法读取的属性进行赋值
  • 不允许删除一个不允许删除的属性
  • 变量名不能使用 "eval" 字符串
  • 变量名不能使用 "arguments" 字符串
  • 由于一些安全原因,在作用域 eval() 创建的变量不能被调用
  • 禁止this关键字指向全局对象

闭包

个人理解的闭包就是能够读取其他函数内部变量的函数

闭包的用途

闭包可以用在许多地方。它的最大用处有两个:

  • 一个是前面提到的可以读取函数内部的变量
  • 另一个就是让这些变量的值始终保持在内存中。

注意点

  • 由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除(如果你没有使用严格模式的话)。
  • 闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值

for...of和for...in的区别

示例一:

window.onload = function () {
    'use strict';
    var array = ['a', 'b', 'c'];
    array.name = 'zeng';
    for (let i in array) {
        console.log(i); // 0, 1, 2, name
    }
}

for...in其实遍历的是对象的属性名称,数组被视为对象,而数组中的元素则被视为属性。但是length属性并不会包含在内。案例二:

window.onload = function () {
    'use strict';
    var array = ['a', 'b', 'c'];
    array.name = 'zeng';
    for (let i of array) {
        console.log(i); // a, b, c
    }
}

所以它才是循环数组本身的值,当然,最好还是使用iterable内置的foreach方法。

window.onload = function () {
    'use strict';
    var array = ['a', 'b', 'c'];
    array.name = 'zeng';
    array.forEach(function (element, index, arr) {
        // element - 元素
        // index - 索引
        // arr - 数组本身
        console.log('循环的数组:' + array + '元素:' + element + ', 索引 = ' + index);
    });
    var sets = new Set(['a', 'b', 'c']);
    sets.forEach(function (element1, element2, s) {
        // element1/element2 - 元素
        // s - set本身
    })

    // map省略,同上
}

position

relation相对定位,参照物是自身,让自身在原本的位置上,通过topleft等属性进行偏移

absolute绝对定位,参照物是具有定位属性的父级节点,如果没有就一直追溯,直到body

fiexd是浏览器定位,参照物是浏览器

static静态定位,默认的,top等属性不会生效

Last modification:March 15th, 2018 at 09:27 pm
If you think my article is useful to you, please feel free to appreciate

One comment

  1. 耐火砖

    这个冒泡真得很让人头疼

Leave a Comment Cancel reply