无标题
JavaScript
运行在客户端的脚本语言,一种基于对象的编程语言(object-baseb)
组成:
ECMAScript
Web APIs
基础语法(ECMAScript)
-
在html文件中的script标签中书写
-
常用的输出语句
1
2
3
4
5
6
7
8
9<script>
//弹出框
alert('hello world')
//控制台输出
console.log('hello world');
//获取用户输出
prompt('hello world')
</script>
常用数据类型
-
基本数据类型
- 字符串:String
- 数字:number
- 布尔:boolean
- 未定义:undefined
- 空:Null
-
复杂数据类型
- 多种数据类型的容器:Object
- 数组:Array
- Function:函数
- RegEXP:正则表达式
- Date:日期
-
利用typeof检测数据类型
常见的就不多说了,讲一下比较特殊的几个,这也是因为JavaScript是一一种弱类型的语言导致的,对类型的检查并不严格
-
undefined 用type检测为它本身,但null类型检测则为Object
-
检测number类型时遇到科学技术法的类型会自动解析,如3e2 就是300,也会解析为number类型
-
检测NaN时,会返回number
-
检测null为Object
-
数组使用typeof检测也为object,不一定正确,主要就是JavaScript是一种弱类型的语言导致的
-
变量提升检测
1
2
3console.log(a);//undefined
console.log(typeof a);//undefined
var a = 10
-
利用字符串拼接
- +,两边都是字符串时就会做拼接操作,有一方为数字也会拼接为字符串,但当字符串前面有+时就会转换为number类型,通常用这种方法来转换用户通过prompt输入的值,通过这个函数获得的值为字符串类型,前面有+则为number类型,会进行隐式提升
字符串
常用函数
函数名 | 功能 |
---|---|
charAt() | 得到指定位置字符串,索引越界会得到空字符串 |
subString() | 截取字符串,前闭后开,参数不接受负数,如果传递的参数前面的比后面大会自动交换两个的位置 |
substr() | 也是截取字符串,接受负数 |
slice() | 提取字符串,参数可以是负数,但参数不会交换位置 |
toUpperCase() | 全部转换为大写 |
toLowerCase() | 转换为小写 |
indexOf() | 检索字符串,返回指定字符串值在字符串中首次出现的位置,匹配不到返回-1 |
数据类型的转换
- Number函数
- 空字符串转换为0
- 不是纯数字的字符串转换为NaN
- 可以识别科学计数法
- null也为0
- undefined 为NaN
- 布尔类型 true为1,false为0
- parselnt函数,将字符串转换为整数
- 传递的是浮点数会自动截取第一位数
- 不会四舍五入
- 不以数字开头转为NaN
- 以数字开头后面的文字会被截取掉
- parseFloat函数
- 不四舍五入
- 可以将小数字符串转换为小数
- 自动截取掉第一个非数字字符
- String函数
- 科学计数法和非十进制数字会转换为十进制的值
- toString
- 几乎所有值都有toString方法,功能就是将值转换为字符串
- Boolean函数
- NaN,0,undefined为false
隐式类型的转换
-
本质就是内部调用Number函数
-
参与运算的操作数不是数字型,会自动将此操作转换为数字
3*'5' //15
-
true+tyue = 2
-
false+2 =2
-
3* ‘2d’ = NaN
-
小数运算不精准,采用指定小数位数解决
1
console.log(Number(0.1+0.2).toFixed(2));
-
数学函数Math
-
幂运算和开根号
1
2Math.pow(2,3)//8
Math.sqrt(4)//2 -
取最大,最小值
1
2Math.max(1,2,3,4,5,6,7,8,9,10)//10
Math.min(1,2,3,4,5,6,7,8,9,10)//1 -
向下向上取整
1
2Math.ceil(1.1)//2
Math.floor(1.9)//1 -
随机数
1
2
3Math.random()//0-1之间的随机数
parseInt(Math.random()*(b-a+1))+a//[a,b]之间的随机数
判断是否相等
-
相等和全等
== 表示的是不比较类型之后的结果,会进行隐式转换后比较值是否相等,也就是1和‘1’相等、
=== 不仅比较值,也比较类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
151 == true //true
1 === true //false
0 == false //true
0 === false //false
0 == undefined //false
0 === undefinde //false
undefined == null //true
undefined === null //false
//NaN 不自等
NaN == NaN //false
NaN === NaN //false
小知识点,逻辑运算的优先级为 非 -> 与 -> 或
函数的定义和调用
- 分为有名称的函数和匿名函数,用function 定义函数
- 形参和实参个数可以不一样 会自动填上undefind
函数声明的提升
-
函数声明能被提升,也就是函数定义在下方但在函数声明上方能调用函数
1
2
3
4
5fun()
function fun(){
alert('hello world')
} -
函数表达式不能被提升,会报错 fun is not a function
1
2
3
4
5fun()
var fun = function fun(){
alert('hello world')
} -
函数优先提升,也就是变量声明的提升,无法覆盖函数的提升
1
2
3
4
5
6
7
8
9
10fun() // B
var fun = function fun(){
alert('A')
}
function fun(){
alert('B')
}
fun() //A
-
函数的参数
-
如果有一个参数没有收到值,则该形参为undefined,undefined进行任何运算的结果都为NaN
-
arguments参数,相当于函数中默认的属性,可变的参数,接受到的实参列表,是一个类数组对象,可以像数组一样通过下表访问元素,但不能调用数组的方法,有length属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14<script>
function fun() {
var sum = 0;
for (var i = 0; i < arguments.length; i++) {
sum += arguments[i];
}
console.log('所有的参数之和为:' + sum); //110
}
fun(33, 22, 55)
</script> -
函数的递归调用,要有终止递归的条件
1
2
3
4
5
6
7
8
9
10
11
12
13
14<script>
//书写一个函数 函数会自己调用自己 从而形成递归
//函数的功能就是计算某个阶乘 n的阶乘就是n*(n-1)的阶乘
function factorial(n) {
//递归的出口 如果计算1的阶乘,可以不用递归了 直接告诉你答案1
if (n == 1) return 1;
//如果询问的不是1的阶乘就返回n*(n-1)!
return n * factorial(n - 1);
}
var result = factorial(6);
console.log(result); //720
</script>
-
闭包
函数本身和该函数声明时所处环境状态的组合,函数能记忆住定义所处的环境,就是不在定义的环境中被调用,也能访问定义时所处的环境变量
也就是在函数中返回一个函数,返回的函数能访问到函数内部的变量,并在外部使用的时候优先调用函数内部的变量,相当于模拟私有变量
滥用闭包可能会导致内存泄漏问题
1 | <script> |
IIFE (立即执行函数)
函数必须要转换为函数表达式才能被调用如 ()(); +function(){}(); -function(){}(); 也可以用于命名函数
可以防止全局变量污染,代码模块化
箭头函数
属于表达式函数,不存在函数提升 ,只有一个参数时可以省略圆括号,只有一行代码省略花括号,并自动作为返回值返回
没有arguments动态参数,可以使用剩余参数
只会沿用自己作用域链上一级的this
深浅拷贝
-
对于基本数据类型,拷贝实在内存中产生新的副本,比较的时候也是比较值是否相等
-
对于引用数据类型,内存中不产生新的值,而是让新变量指向同一个对象,比较的时候也是比较内存地址是否相同
-
当我们引用的对象内存地址是相同的时候,改变其中一个变量的值,另一个变量也会跟着改变
解决方法:通过递归实现深拷贝
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38const obj = {
uname: 'pink',
age: 18,
hobby: ['乒乓球', '足球'],
family: {
baby: '小pink'
}
}
const o = {}
// 拷贝函数
function deepCopy(newObj, oldObj) {
debugger
for (let k in oldObj) {
// 处理数组的问题 一定先写数组 在写 对象 不能颠倒
if (oldObj[k] instanceof Array) {
newObj[k] = []
// newObj[k] 接收 [] hobby
// oldObj[k] ['乒乓球', '足球']
deepCopy(newObj[k], oldObj[k])
} else if (oldObj[k] instanceof Object) {
newObj[k] = {}
deepCopy(newObj[k], oldObj[k])
}
else {
// k 属性名 uname age oldObj[k] 属性值 18
// newObj[k] === o.uname 给新对象添加属性
newObj[k] = oldObj[k]
}
}
}
deepCopy(o, obj) // 函数调用 两个参数 o 新对象 obj 旧对象
console.log(o)
o.age = 20
o.hobby[0] = '篮球'
o.family.baby = '老pink'
console.log(obj)
console.log([1, 23] instanceof Object)
// 复习通过lodash实现深拷贝
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16<!-- 先引用 -->
<script src="./lodash.min.js"></script>
<script>
const obj = {
uname: 'pink',
age: 18,
hobby: ['乒乓球', '足球'],
family: {
baby: '小pink'
}
}
const o = _.cloneDeep(obj)
console.log(o)
o.family.baby = '老pink'
console.log(obj)
</script>通过JSON对象实现深拷贝
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15<script>
const obj = {
uname: 'pink',
age: 18,
hobby: ['乒乓球', '足球'],
family: {
baby: '小pink'
}
}
// 把对象转换为 JSON 字符串
// console.log(JSON.stringify(obj))
const o = JSON.parse(JSON.stringify(obj))
console.log(o)
o.family.baby = '123'
console.log(obj)
变量
- 局部变量,在函数或语句内部定义的,如果局部变量中的变量名和全局变量变量名相同,那在函数执行过程中,变量的值以局部变量为准
- 全局变量,不给变量加var 或 let 在函数中定义的也是全局变量(应该就是他的父类对象为window)
Web APIs
DOM(文档对象模型)
将文档表现为节点树,根为document对象,表示整个HTML文档
document对象
节点
访问元素节点的常用方法
方法 | 功能 | 兼容 |
---|---|---|
document.getElementById() | 通过id获取元素 | IE6 |
document.getElementByTageName() | 通过标签名获取元素 | IE6 |
document.getElementByClassName() | 通过类名获取 | IE9 |
document.querySelector() | 通过选择器获取 | IE8部分 IE9 |
doocumentt.querySelectorAll() | 通过选择器获取元素数组 | IE8部分 IE9 |
节点之间的关系
-
改变节点中的元素内容可以用 innerHTMl innerText 这两个属性
-
改变元素节点的CSS样式,style.要改变的CSS属性 注意要写成驼峰的形式
-
创建新节点并插入,删除节点,只能通过父节点删除
1
2
3
4
5const parent = document.querySelector('div')
const child = document.createAttribute('div')
parent.appendChild(child) //在父元素的末尾添加子元素
parent.insertBefore(child,parent.children[0])//在父元素的第一个子元素前添加子元素
parent.removeChild(child)//删除子元素
事件
事件监听
事件:用户与网页的交互动作
1 | <script> |
-
常见的鼠标事件监听
-
常见的键盘事件监听
-
表单事件监听
事件传播
从外到内在从内到外,JavaScript中分为捕获阶段和冒泡阶段,捕获阶段就是从外到内的过程,冒泡阶段就是从内到外的过程
- 有两种事件监听的方法
- document对象.onclick DOM0级的事件,只能监听冒泡阶段,后面写的会覆盖前面写的
- document对象.addEventListener(‘事件类型’,事件处理函数) DOM2级事件,会按顺序执行,匿名函数无法解绑
- 事件对象,事件处理函数中有一个对象,通常用e或event表示,可以通过这个对象定位到选择的元素
事件委托

定时器和延时器
定时器
setInterval 以固定时间重复调用一个函数,clearInterval这个方法清除定时器,定时器开启的时候可以用一个变量来接收
具体使用
1 | var a = 0; |
延时器
setTimeout 设置 指定时间会执行函数一次,clearTimeout清除延时器
1 | const box = document.querySelector('.box') |
抛出异常和捕获异常
抛出异常
1 | function fn(x, y) { |
try-catch语句
1 | function fn() { |
this的指向
谁调用就指向谁,注意有个父类对象window,像一些内置函数的指向就是它
1 | // 普通函数: 谁调用我,this就指向谁 |
具体实例
1 | var arr = ['a', 'b', 'c', function () { |
改变this的指向
call 和 apply 的区别 call 用,罗列参数 apply用数组
-
call函数
1
2
3
4
5
6
7
8
9
10
11const obj = {
uname: 'pink'
}
function fn(x, y) {
console.log(this) // window
console.log(x + y) //NaN
}
// 1. 调用函数
// 2. 改变 this 指向 改变后this就指代的是obj 对象
fn.call(obj, 1, 2)
// fn() -
apply函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21const obj = {
age: 18
}
function fn(x, y) {
console.log(this) // {age: 18}
console.log(x + y)
}
// 1. 调用函数
// 2. 改变this指向
// fn.apply(this指向谁, 数组参数)
fn.apply(obj, [1, 2])
// 3. 返回值 本身就是在调用函数,所以返回值就是函数的返回值
const arr = [100, 44, 77]
const max = Math.max.apply(Math, arr) //100
const min = Math.min.apply(null, arr) //44
console.log(max, min)
// 使用场景: 求数组最大值
console.log(Math.max(arr));//NaN
console.log(Math.max(...arr))// 100 -
bind函数,和上面两个不同的是它的返回值是函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23const obj = {
age: 18
}
function fn() {
console.log(this)
}
// 1. bind 不会调用函数
// 2. 能改变this指向
// 3. 返回值是个函数, 但是这个函数里面的this是更改过的obj
const fun = fn.bind(obj)
// console.log(fun)
fun()
// 需求,有一个按钮,点击里面就禁用,2秒钟之后开启
document.querySelector('button').addEventListener('click', function () {
// 禁用按钮
this.disabled = true
window.setTimeout(function () {
// 在这个普通函数里面,我们要this由原来的window 改为 btn
this.disabled = false
}.bind(this), 2000) // 这里的this 和 btn 一样
})
BOM(浏览器对象模型)
浏览器中的每个标签页都有一个window对象,全局变量会成为window的属性,多个JS文件之间是共享作用域的,没有作用域隔离的功能,内置函数一般都是window的方法
浏览器窗口属性
1 | console.log(window.innerHeight);//浏览器窗口高度 |
-
窗口大小改变后会触发resize事件
1
2
3
4
5window.onresize = function(){
var root = document.documentElement;
console.log(root.clientWidth); //窗口尺寸改变时,获取窗口宽度
console.log(root.clientHeight); //窗口尺寸改变时,获取窗口高度
} -
获得卷积高度
1
2
3
4
5
6
7//卷积事件监听
window.scrollY //只读
document.documentElement.scrollTop //可以改变
window.onscroll = function(){
console.log(document.documentElement.scrollTop);//窗口卷积高度
console.log(document.documentElement.scrollLeft);//窗口卷积宽度
} -
Navigator对象,包含用户使用浏览器的信息和操作系统
1
2
3
4
5
6
7
8
9
10console.log(navigator.appCodeName); //浏览器代码名
console.log(navigator.appName); //浏览器名称
console.log(navigator.appVersion); //浏览器版本
console.log(navigator.userAgent); //浏览器信息
console.log(navigator.platform); //浏览器平台
console.log(navigator.cookieEnabled); //是否启用cookie
console.log(navigator.javaEnabled()); //是否启用java
console.log(navigator.language); //浏览器语言
console.log(navigator.onLine); //是否在线
console.log(navigator.userAgentData); //浏览器信息 -
History对象,模拟浏览器的回退按钮
1
2
3
4history.back(); //返回上一页
history.forward(); //前进下一页
history.go(-1); //返回上一页
history.go(1); //前进下一页 -
Location对象
1
2
3
4location.href = "https://www.baidu.com"; //跳转页面
location.reload(true); //刷新页面,强制从服务器加载
location.replace("https://www.baidu.com"); //替换页面
location.assign("https://www.baidu.com"); //跳转页面
对象
键值对的集合,表示属性和值的映射关系
构造函数和原型对象中的this都指向实例化的对象
语法规则
-
定义一个对象
1
2
3
4
5
6var person = {
firstName:"John",
lastName:"Doe",
age:50,
eyeColor:"blue"
}; -
访问当中的元素
1
2
3person.lastName;
person["lastName"];
//但当属性名不符合规范的时候只能通过[]的形式访问、如果属性名以变量的方式存储也要用[]的形式访问 -
属性的赋值和新增
使用赋值运算符,没有属性用创建的那个对象加点就会创建出这个属性
-
属性的删除
1
2
3
4
5
6var obj = {
name: 'pink',
age: 18
}
delete obj.name
console.log(obj) -
对象的遍历
1
2
3
4
5
6
7
8
9
10
11var obj = {
name: 'pink',
age: 18,
sayHi: function () {
console.log('hi')
}
}
for (var key in obj) {
console.log("key:" + key + " value:" + obj[key])
}
new出来的对象
用new方法调用函数,函数内会自动创建出一个空白对象,函数中的this会指向这个对象,函数体内的语句会执行
会自己返回上下文对象,即使没有return语句
new 调用的函数也叫做构造函数,记得首字母大写(约定),构造函数通常是给对象赋值用的,如果不用new调用函数,它里面的this就不是本身
1 | function Person(name, age) { |
对象的原型链查找
任何函数都有prototype属性,该属性值是一个对象,默认有constructor属性指回函数
构造函数的prototype属性是它的实例的原型
实例可以通过.来访问原型的属性和方法
-
图解关系
-
代码实现
1
2
3
4
5
6
7
8
9
10function Star() {
}
const ldh = new Star()
// 对象原型__proto__ 指向 改构造函数的原型对象
console.log(ldh.__proto__)
// console.log(ldh.__proto__ === Star.prototype)
// 对象原型里面有constructor 指向 构造函数 Star
console.log(ldh.__proto__.constructor === Star)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// function Objetc() {}
console.log(Object.prototype) // {}
console.log(Object.prototype.__proto__) // null
function Person() {
}
const ldh = new Person()
// console.log(ldh.__proto__ === Person.prototype)
// console.log(Person.prototype.__proto__ === Object.prototype)
console.log(ldh instanceof Person) // true
console.log(ldh instanceof Object) // true
console.log(ldh instanceof Array) // false
console.log([1, 2, 3] instanceof Array) // true
console.log(Array instanceof Object) // true
具体使用
如果将方法直接添加到实例身上会造成内存的浪费,每个实例和每个实例的方法函数都是内存中不同的函数,造成了内存的浪费
将方法添加到prototype就可以解决这个问题
-
通过原型链实现继承
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42// 继续抽取 公共的部分放到原型上
// const Person1 = {
// eyes: 2,
// head: 1
// }
// const Person2 = {
// eyes: 2,
// head: 1
// }
// 构造函数 new 出来的对象 结构一样,但是对象不一样
function Person() {
this.eyes = 2
this.head = 1
}
// console.log(new Person)
// 女人 构造函数 继承 想要 继承 Person
function Woman() {
}
// Woman 通过原型来继承 Person
// 父构造函数(父类) 子构造函数(子类)
// 子类的原型 = new 父类
Woman.prototype = new Person() // {eyes: 2, head: 1}
// 指回原来的构造函数
Woman.prototype.constructor = Woman
// 给女人添加一个方法 生孩子
Woman.prototype.baby = function () {
console.log('宝贝')
}
const red = new Woman()
console.log(red)
// console.log(Woman.prototype)
// 男人 构造函数 继承 想要 继承 Person
function Man() {
}
// 通过 原型继承 Person
Man.prototype = new Person()
Man.prototype.constructor = Man
const pink = new Man()
console.log(pink)
多级对象解构
只取出我们需要的数据 {}
1 | // 1. 这是后台传递过来的数据 |
包装类
-
数组 Array
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54const arr = [
{
name: '小米',
price: 1999
},
{
name: '华为',
price: 3999
},
]
// 找小米 这个对象,并且返回这个对象
// const mi = arr.find(function (item) {
// // console.log(item) //
// // console.log(item.name) //
// console.log(111)
// return item.name === '华为'
// })
// 1. find 查找 放回的是找到的对象
const mi = arr.find(item => item.name === '小米')
// console.log(mi)
// 2. every 每一个是否都符合条件,如果都符合返回 true ,否则返回false
const arr1 = [10, 20, 30]
const flag = arr1.every(item => item >= 20)
// 求和
const arr = [1, 2, 3]
const re = arr.reduce((prev, item) => prev + item)
// 过滤 返回一个新数组
const re1 = arr.filter(item => item > 2)
arr.push(4) // 添加
arr.pop() // 删除
arr.shift() // 删除第一个
arr.unshift(1) // 添加第一个
arr.splice(1, 1) // 删除
arr.splice(1, 0, 2) // 添加
console.log(re)
console.log(re1)
arr.forEach(item => {
console.log(item)
})
// 映射 返回一个新数组
const re2 = arr.map(item => {
return item * 2
})
// Array.from(lis) 把伪数组转换为真数组
const lis = document.querySelectorAll('ul li')
// console.log(lis)
// lis.pop() 报错
const liss = Array.from(lis)
liss.pop()
console.log(liss)
-
日期类 Data
1
2
3
4
5
6
7
8
9
10const date = new Date()
console.log(date.getFullYear()); // 年
console.log(date.getMonth() + 1); // 月
console.log(date.getDate()); // 日
console.log(date.getHours()); // 时
console.log(date.getMinutes()); // 分
console.log(date.getSeconds()); // 秒
console.log(date.getDay()); // 星期
console.log(date.getTime()); // 时间戳
正则表达式
匹配字符串中字符组合的模式
常用方法
1 | const regObj = /a/g |
修饰符
-
i 忽略大小写
-
g 全局匹配
-
m 多行匹配
-
u 匹配unicode编码
-
y 匹配开始位置