冒泡事件
“冒泡”这个词就能想到肯定是从底部往上升,而冒泡事件就是在第一层定义的事件,在顶层也会被触发。
<!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上的解释:
捕获阶段:
- 浏览器会检查最外层的祖先
html
,是否在捕获阶段注册了onclick
事件,如果是,则执行它。 - 接着,移动到
html
中的下一个元素,并执行第一步,依次往后推,直到达到被点击的元素为止。
- 浏览器会检查最外层的祖先
冒泡阶段:
- 浏览器先检查被点击的对象是否注册了
onclick
事件,如果是,则执行它。 - 然后移动到它下一个最直接的父元素,然后执行相同的操作,依次往后推,直到
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
是相对定位,参照物是自身,让自身在原本的位置上,通过top
、left
等属性进行偏移
absolute
是绝对定位,参照物是具有定位属性的父级节点,如果没有就一直追溯,直到body
fiexd
是浏览器定位,参照物是浏览器
static
静态定位,默认的,top
等属性不会生效
这个冒泡真得很让人头疼