事件
事件是给浏览器定义一个预处理函数,当事件触发的时候,执行函数,这就是事件。
添加事件的方式
事件绑定
这是一种赋值的方式,一个元素的同类型事件只能绑定一个,而且事件触发都是冒泡阶段处理的。
document.onclick = function () {
console.log('clicked')
}
取消绑定:赋值为null把函数覆盖即可
document.onclick = null
事件监听
给元素添加事件监听器,一个元素同类型事件可以同时监听多个,先监听先触发
而且在非IE的浏览器里可以指定处理阶段,在addEventListener的第三个参数去传(冒泡或者捕获)
写法有兼容
// 非IE
document.addEventListener('click', function () {
console.log('clicked')
}, false)
// IE
document.attachEvent('onclick', function () {
console.log('clicked')
})
移除监听
removeEventListener
detachEvent
或者直接使用我们utils.js里封装好的on和off方法
事件对象
当事件被触发的时候可以从事件函数的参数里得到一个关于当前事件得一些信息,这个对象里包含了各种当前事件的方法和属性
事件对象获取(兼容)
document.onclick = function (e) {
e = e || window.event
console.log(e)
}
事件对象的常见属性
鼠标事件里的坐标
属性名 | 含义 |
---|---|
e.offsetX / offsetY | 获取事件触发最近的盒子(事件源)的坐标 |
e.clientX / clientY | 获取可视区的坐标(根据浏览器的定位) |
e.screenX / screenY | 获取整个屏幕的坐标 |
e.pageX / e.pageY | 获取文档的坐标(包含滚动条) |
键盘事件里的键码
可以在键盘事件里获取当前按下的键码
document.onkeydown = function (e) {
e = e || window.event
var code = e.keyCode || e.which
console.log(code)
}
功能键的特殊键码
e.altKey
e.ctrlKey
e.shiftKey
返回值是布尔值;
可以用来判断组合键
if (e.keyCode === 13 && e.altKey) {
alert('同时按下了enter和alt')
}
默认行为
有一些html元素默认的行为,比如说a标签,点击后有跳转动作;form表单中的submit类型的input有一个默认提交跳转事件;reset类型的input有重置表单行为。(不写任何js代码也会触发的行为)
但是,有些时候我们是不需要默认事件的,所以就需要阻止默认事件
if(e.preventDefault) {
e.preventDefault()
}else {
window.event.returnValue = false
//return false
}
事件流
一个完整事件包含 捕获阶段 —> 目标阶段 —>冒泡阶段
但是一般都在冒泡阶段处理,在非IE监听事件addEventListener的时候可以决定在冒泡或者捕获的时候处理事件
但是IE浏览器不支持捕获阶段处理
事件冒泡
子元素的事件或通过冒泡传播到父级以及祖先
但是冒泡有些时候并不需要,可以阻止
if (e.stopPropagation) {
e.stopPropagation()
} else {
e.cancelBubble = true
}
事件委托
利用事件冒泡,只指定一个事件处理程序,就可以处理某一类型的所有事件。使用场景主要用于事件源不确定的情况,可以把子元素的事件事件委托给父级
事件委托的原理就是事件冒泡
获取事件源
var target = e.target || e.srcElement
一般也会在获取到了事件源以后对他做一些判断,比如通过 tagName、className、id或者其他属性来判断事件源是谁,来进行对应操作
优点:
- 简单,方便
- 可以为不确定的元素绑事件
案例:表格编辑
ES5/ES6
ECMA组织定义js核心语法的标准,这个标准几乎每一年都会更新,我们会简称为ES版本,ES6就是ES2015,但是其实现在提到ES6不止是2015年的标准,而是新一代的ES,也叫ES Next
ES5
严格模式(不常用,但是要知道)
js的一种更加严格的运行模式,严格模式在开发中一般不会特意去使用,但是我们可以用严格模式来要求自己的代码
进入严格模式使用一个字符串 ‘use strict’,只要在某歌js文件开头写了这个字符串那么后面的代码全都是严格模式
如果在一个函数开头 ‘use strict’那就是这个函数在运行的时候以严格模式来运行
严格模式下的一些变更
- 声明变量必须用关键字来声明(var\let\const)
- 全局函数的this无法指向全局对象window,而是undefined
- 函数参数不允许重名(非严格模式下重名后面的覆盖前面的)
- 函数的arguments不能被动态改变
- 新增保留字; implements, interface, let, package, private, protected, public, static, yield(但是目前浏览器大多已经支持ES6了,所以这些保留字很多已经是关键字了)
ES5新增常见方法
Array API
2个索引方法:indexOf() 和 lastIndexOf()
5个迭代方法:forEach()、map()、filter()、some()、every()
2个归并方法:reduce()、reduceRight()
String API
trim();// 去掉字符串前后空格
trimLeft()
trimRight()
新增的对象方法(前三个很重要)
JSON.parse(str); //json序列化,将符合json格式的字符串转换为json
JSON.stringify(); //json转换为字符串
Date.now(); //日期对象得到当前日期的毫秒数
Object API
Object.keys(obj); //获取obj的所有属性名称,返回数组
Object.values(obj); // 获取obj的所有属性值,返回数组
Object.defineProperty(obj, prop, option); //给obj设置属性
var obj = new Object();
Object.defineProperty(obj, 'name', {
configurable: false, // 表示能否通过delete删除此属性
writable: true, // 能否修改属性的值
enumerable: true, // 表示该属性是否可枚举,即是否通过for-in循环或Object.keys()返回属性
value: '张三'
})
console.log(obj.name)
Object.defineProperties(obj, props); // 一口气定义多个属性,原理和defineProperty一样
Object.assign 合并对象
一般第一个参数写{},这样就不会影响本来的对象而是返回一个新的
var obj1 = {
name: 'lisi'}
var obj2 = {
age: 19}
var obj3 = {
gender: 'male'}
var obj4 = Object.assign({
}, obj1, obj2, obj3)
console.log(obj4)
ES6
let
块级作用域,只在当前块级里有效,所谓的块级简单理解就是 {}
-
let没有变量提升
-
暂时性死区
案例:点击li弹出下标
const
声明常量,不能被重新赋值的量
注意:引用类型(数组,对象,函数)可以使用他的API去修改内部结构,但是不能赋值(不能修改地址)
扩展运算符 …
可以把数组或者对象展开成一系列逗号隔开的值
- 数组展开以后可以作为函数参数去传递或者用另外一个数组来接收
- 对象展开以后只能用另外一个对象来接收
- 可以用来复制数组或者对象
rest运算符 …
跟扩展运算符写法一样,用来把一系列逗号隔开的值合并成一个数组
可以用来把函数的实参合并到一个形参里
String API
repeat
includes(使用最多的)
startsWith
endsWith
字符串模板
使用``来写字符串,这样可以直接换行,也可以通过${}里面写表达式会直接解析
一般用来拼接HTML字符串非常实用
=>箭头函数
var test = () => { … }
-
如果形参只有一个,小括号可以省略
-
如果函数只有一句话而且这句话就是返回值,那么{}和return关键字都可以省略
但是要注意:如果返回的是对象,则要再加一层()
箭头函数没有自己的this
- 如果你希望this指当前对象,那么就用普通函数
- 如果你希望this指向外层对象,用箭头函数
- 如果内层外层都要,用普通函数,this指内层,在外层声明一个变量把外层this存下来,比如 const _this = this,_this指外层
解构赋值
解构数组或者对象
数组是按顺序解构
对象按属性名解构
另外一种用法
var age = 20
var username = 'lisi'
var gender = 'male'
var obj = {
age, username, gender }
class、set,map、Symbol
利用set去重
var arr1 = [4,32,3,32,2,43,2,4]
var arr2 = [ ...new Set(arr1) ]
面向对象
构造函数
构造一个对象的函数,一般首字母大写
因为在js里没有类,所以构造函数相当于是一个抽象类
原型
prototype属性,函数的伴生体,构造函数的原型是给所有实例共享属性和方法的地方
实例的__proto__ 指向构造函数的prototype
原型一层一层往上查找的过程称之为原型链
Object.prototype.__proto__ === null,这是原型链的终点
js一切皆为对象:因为所有数据都会沿着原型链找到Object.prototype
instanceof 运算符,判断当前对象是否是另一个对象的实例,用它可以判断一个数据是否是数组
constructor prototype里面的constructor指向当前对象的构造函数
this
this指的是当前上下文对象,意思就是当前正在执行的是哪个函数,this就指向当前函数的调用对象(箭头函数除外)
箭头函数没有自己的this
bind 封装函数的时候改变this
call 调用函数的时候改变this(传参就依次往后传递即可)
apply 调用函数的时候改变this(传参需要放到数组里传)
兼容问题
说明 | 写法 |
---|---|
滚动条滚轮高度 | document.documentElement.scrollTop || document.body.scrollTop |
事件对象 | e = e || window.event |
阻止默认行为 | e.preventDefault() return false |
阻止冒泡 | e.stopPropagation() e.cancelBubble = true |
键盘键码 | e.keyCode || e.which |
事件源 | e.target || e.srcElement |
添加事件监听 | addEventListener attachEvent |
移除事件监听 | removeEventListener detachEvent |
获取元素最终样式 | getComputedStyle currentStyle |
获取浏览器宽度 | document.documentElement.clientWidth || document.body.clientWidth |