【JS的BOM】操作浏览器

操作浏览器的一些内容。

获取窗口尺寸

  1. 宽度:window.innerWidth
  2. 高度:window.innerHeight

弹出层

  1. 提示框:window.alert()
  2. 询问框:window.confirm()
  3. 输入框:window.prompt()

标签页的开启和关闭

  1. 开启:window.open()
  2. 关闭:window.close()

历史操作记录

  1. 回退:window.history.back()
  2. 前进:window.history.forward()

浏览器常见事件

  1. 资源加载完毕:window.onload = function () {}
  2. 页面尺寸改变:window.onresize = function () {}
  3. 滚动条位置改变:window.onscroll = function () {}

滚动条卷去的尺寸

当 HTML 页面有<!DOCTYPE html>时用第一种代码,没有时用第二种代码。
书写代码时可以都写上:var height = document.documentElement.scrollTop || document.body.scrollTop

  • 高度:
    1. document.documentElement.scrollTop
    2. document.body.scrollTop
  • 宽度:
    1. document.documentElement.scrollLeft
    2. document.body.scrollLeft

浏览器滚动到

  • window.scrollTo()
    • 例子1
      1
      window.scrollTO( left, top)
    • 例子2
      1
      2
      3
      4
      5
      window.scrollTo( {
      left: xx,
      top: yy,
      behavior: 'smooth'
      } )

【JS定时器】

间隔定时器

按照指定周期(毫秒)去执行指定的代码

像定时闹钟,可重复执行

  • 语法:setInterval(函数, 时间)
    1. 函数:要执行的内容
    2. 时间:单位毫秒
1
2
3
setInterval(function () {
console.log( '执行一次' )
}, 1000)

延时定时器

在固定的时间(毫秒)后指定一次代码

像延时炸弹,只执行一次

  • 语法:setTimeout(函数, 时间)
    1. 函数:时间到达时要执行的内容
    2. 时间:单位毫秒
1
2
3
setTimeout(function () {
console.log( '执行一次' )
}, 3000)

定时器的返回值

不区分定时器的种类,是个从1开始的正整数,

返回值表示:是当前页面的第几个定时器

关闭定时器

语法一:clearInterval(要关闭的定时器返回值)

语法二:clearTimeout(要关闭的定时器返回值)

注意:不区分定时器种类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<button id="close">关闭定时器</button>

<script>
// 开启定时器1
var timer1 = setInterval(function () { console.log('间隔定时器') }, 1000)
// 开启定时器2
var timer1 = setTimeout(function () { console.log('间隔定时器') }, 3000)

// 给按钮绑定点击事件
close.onclick = function () {
// 关闭定时器
clearInterval(timer1) //不区分定时器种类也就是说只用管括号内到底是timer1还是timer2就行了,
clearTimeout(timer2) //前面是clearInterval还是clearTimeout都行,哪个无所谓
}
</script>

【JS的DOM操作】(上)

操作文档流相关的内容和方法

一、获取元素的方式

1. 根据id名称

语法:document.getElementById( 'id名称' )

作用:获取文档流中 id 名对应的一个元素

返回值:

  1. 如果有 id 对应的元素,就是这个元素
  2. 如果没有 id 对应的元素,返回null

2. 根据类名

语法:document.getElementsByClassName( '元素类名' )

作用:获取文档流中所有类名对应的元素(上面Element后有s)

返回值:必然是一个伪数组

  1. 如果有类名对应的元素,有多少取多少
  2. 如果没有类名对应的元素,返回空的伪数组

3. 根据标签名

语法:document.getElementsByTagName( '标签名' )

作用:获取文档流中所有标签名对应的元素(上面Element后有s)

返回值:必然是一个伪数组

  1. 如果有标签名对应的元素,有多少取多少
  2. 如果没有标签名对应的元素,返回空的伪数组

4. 根据选择器获取一个

语法:document.querySelector( '选择器' )

作用:获取文档流中满足选择器的第一个元素

返回值:

  1. 如果有选择器对应的元素,获取到第一个
  2. 如果没有标签名对应的元素,返回null

5. 根据选择器获取一组

语法:document.querySelectorAll( '选择器' )

作用:获取文档流中所有满足选择器的元素

返回值:必然是一个伪数组

  1. 如果有选择器对应的元素,有多少取多少
  2. 如果没有选择器对应的元素,返回空的伪数组

二、操作元素的内容

文本内容

  1. 获取:元素.innerText
  2. 设置:元素.innerText = '新内容'

超文本内容

  1. 获取:元素.innerHTML
  2. 设置:元素.innerHTML = '新内容'

三、操作元素属性

原生属性

  1. 获取:元素.属性名
  2. 设置:元素.属性名 = '属性值'

自定义属性

  1. 获取:元素.getAttribute( '属性名' )
  2. 设置:元素.getAttribute( '属性名', '属性值' )'
  3. 删除:元素.removeAttribute( '属性名' )

四、操作元素类名

  1. 获取:元素.className
  2. 设置:元素.className = '新类名'

注意:在获取background-color这种带有中划线的属性时,要改成backroundColor这种驼峰命名法
比如console.log( box.style.backroundColor )
又如box.style.backroundColor = 'green'

五、操作元素行内样式

  1. 获取:元素.style.样式名
  2. 设置:元素.style.样式名 = '样式值'

注意:只能获取和设置元素的行内样式

六、获取元素非行内样式

获取:window.getComputedStyle(元素).样式名

注意:可以获取行内样式,也可以获取非行内样式


【案例】通栏收起/全选/Tab切换

  1. 顶部通栏的收起与隐藏,以及回到顶部的按钮:教程视频
  2. 全选:教程视频(注意视频中for循环内应该用let来声明变量,详情请见→讲解博文
  3. 选项卡(Tab切换):教程视频(用到了遍历数组的forEach()方法)

【JS的DOM操作】(下)

一、节点操作

创建

语法:document.createElement( '标签名称' )

作用:创建一个指定标签元素

返回值:一个创建好的标签元素节点

1
2
var div = document.createElement( 'div' )
console.log(div)

插入

需要先执行上面代码创建一个节点,然后执行下面代码插入到一个已经存在的结构内。

  • 语法一:父节点.appendChild( 子节点 )
    作用:把子节点放在父节点的内部,并且放在最后的位置

  • 语法二:父节点.insertBefore( 要插入的子节点, 哪一个子节点的前面 )
    作用:把子节点放在父节点的内部,并且放在指定某一个子节点的前面

删除

  • 语法一:父节点.removeChild( 子节点 )
    作用:从父节点内删除某一个子节点

  • 语法二:节点.remove()(无参数)
    作用:把自己删除

替换

语法:父节点.replaceChild( 换上节点, 换下节点 )

作用:在父节点内,使用换上节点替换掉换下节点

克隆

语法:节点.cloneNode( 是否克隆后代节点 )

作用:把该节点复制一份一模一样的内容

二、获取元素的尺寸

  • 语法一:元素.offsetHeight元素.offsetWidth
    获取:元素“内容 + padding + border”区域的尺寸

  • 语法二:元素.clientHeight元素.clientWidth
    获取:元素“内容 + padding”区域的尺寸

两个语法的区别是:是否加上边框


【案例】动态渲染数据

视频教程

如拿到数据后渲染成表格到前端页面


【JS的事件】(上)

通俗地讲,就是通过代码的方式和页面中的某些内容做好一个约定(事件绑定)
当用户触发指定行为的时候,就会执行代码

事件绑定

三要素:

  1. 事件源:和谁做约定
  2. 事件类型:约定什么行为
  3. 事件处理函数:当用户触发该行为的时候,执行什么代码

语法:事件源.on = 事件处理函数

要提前获取该元素哦!

事件类型

事件类型

事件对象

就是当事件触发的时候,一个描述该事件信息的对象数据类型.

方法很简单,直接在上面说的那些事件处理函数内接受形参就可以了:

1
2
3
4
// 直接在事件处理函数内接受形参
div.onclick = function (e) {
console.log(e)
}

获取到的有很多信息,常见的如下:

1. 鼠标事件

坐标信息:

  1. offsetXoffsetY
  2. clientXclientY
  3. pageXpageY

2. 键盘按键

键盘编码:事件对象.keyCode


【案例】鼠标跟随

视频教程


【JS的事件】(下)

事件传播

就是浏览器响应事件的总机制
浏览器的事件响应机制

浏览器的事件响应机制:

  1. 浏览器最先知道事件的发生
  2. 捕获阶段:从Window按照结构子级的顺序传递到目标
  3. 目标阶段:准确触发事件的那个元素接收到行为
  4. 冒泡阶段:从目标按照结构子级的顺序传递到Window

浏览器的传播机制默认都是在冒泡阶段触发事件的,点击子级时,子级触发事件并往外传播给父级,如果父级也绑定了事件,也会触发父级的,比如下面的例子,点击最里层的inner,这三个嵌套在一起的元素都会被触发。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<div class="outer">
<div class="center">
<div class="innner"></div>
</div>
</div>

<script>
// 绑定事件
// 1. 获取到需要用到的元素
var outer = document.querySelector('.outer')
var center = document.querySelector('.center')
var innner = document.querySelector('.innner')

// 给三个元素都绑定点击事件
outer.onclick = function () { console.log('我是 outer 元素,我被点击了') }
center.onclick = function () { console.log('我是 center 元素,我被点击了') }
innner.onclick = function () { console.log('我是 innner 元素,我被点击了') }
</script>

阻止事件传播

语法:事件对象.stopPropagation()

比如在上面那个案例中innner的onclick事件添加个参数e(作为事件对象),在代码里添加上方语句后只触发inner自己的事件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<div class="outer">
<div class="center">
<div class="innner"></div>
</div>
</div>

<script>
// 绑定事件
// 1. 获取到需要用到的元素
var outer = document.querySelector('.outer')
var center = document.querySelector('.center')
var innner = document.querySelector('.innner')

// 给三个元素都绑定点击事件
outer.onclick = function () { console.log('我是 outer 元素,我被点击了') }
center.onclick = function () { console.log('我是 center 元素,我被点击了') }
innner.onclick = function (e) {
// 阻止事件传播
e.Propagation()
console.log('我是 innner 元素,我被点击了') }
</script>

事件委托

利用事件冒泡的机制,把自己的事件委托给结构父级中的某一层。

比如下方代码,无论点击的是哪个 li 元素,绑定点击事件的 ul 元素都会触发事件。

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
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>

<script>
// 事件委托
// 1. 获取到 ul 元素
var ul = document.querySelector('ul')

// 给 ul 绑定点击事件
ul.onclick = function () {
console.log('点击事件触发')
}
</script>

<style>
li {
width: 60px;
height: 60px;
background-color: rgb(245, 132, 194);
color: #000;
text-align: center;
line-height: 60px;
margin: 10px;
}
ul {
width: 500px;
height: 200px;
background-color: rgb(35, 195, 216);
color: #000;
display: flex;
justify-content: center;
align-items: center;
font-size: 20px;
cursor: pointer;

list-style: none;
padding: 0;
margin: 0;
}
</style>

那如何确定点击的是哪一个 li 元素?或者点击的是不是 ul 呢?我们把上面中的JS里,加入形参e作为事件对象,运用target属性,target拿到的就是你点击的那个元素:

1
2
3
4
5
6
7
8
9
// 事件委托
// 1. 获取到 ul 元素
var ul = document.querySelector('ul')

// 给 ul 绑定点击事件
ul.onclick = function (e) {
console.log('点击事件触发')
console.log(e.target)
}

上面的写法中,根据你点击的元素,控制台打印出的可能是<ul></ul><li>3</li>

我们换一种写法,利用 target 的 tagName 属性(就是target获取的标签元素的大写标签名):

1
2
3
4
5
6
7
8
9
10
// 事件委托
// 1. 获取到 ul 元素
var ul = document.querySelector('ul')

// 给 ul 绑定点击事件
ul.onclick = function (e) {
// 通过事件目标来判断你点击的是 li
if (e.target.tagName === 'LI') {
console.log('你点击的是 li')
}

这样写之后,点击 ul 不会触发了。点击任何的 li 都会触发,这就是事件委托。


【案例】轮播图

视频教程


【面向对象】

一、了解面向对象

了解面向对象:面向对象是我们的一种开发方式。视频讲解

  • 面向过程:一种关注过程的开发方式
    => 在开发过程中,我们要关注每一个细节、步骤,顺序

  • 面向对象:一种面向对象的开发方式
    => 在开发过程中,我们看看有没有一个对象能帮我们完成任务

面向对象的核心:高内聚低耦合(就是对面向过程的高度封装)

二、创建对象的方式

视频讲解

1. 字面量方式创建对象

1
2
var obj = { ... }
// 可以后期动态添加
1
2
3
4
5
var obj = { 
name: 'jack'
age: 18
sayHi: function () { console.log('hello world') }
}

2. 内置构造函数方式创建对象

1
2
var obj = new Object()
// 可以后期动态添加
1
2
3
4
var obj = new Object()
obj.name = 'jack'
obj.age = 18
obj.sayHi = function () { console.log('hello world') }

3. 工厂函数创建对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 1.制造一个工厂函数
function createObj( name, age) {
// 1.1 手动创建一个对象
var obj = {}

// 1.2 手动向里面添加属性
obj.name = name
obj.age = age
obj.sayHi = function () { console.log('hello world') }

// 1.3 手动返回对象
return obj
}

// 2.使用工厂函数去创建对象
var obj1 = createObj('Jack', 18)
var obj2 = createObj('Rose', 20)
console.log(obj1, obj2)

工厂模式有返回值,因为通过调用函数会把把函数返回值(这里就是函数封装的对象obj)给返回,然后我们通过声明一个变量obj1去接收,此时变量obj1里面存的就是对象,然后通过对象调用属性与方法,如果没有返回值就会报错。

4. 自定义构造函数创建对象

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
// 1.制造一个自定义构造函数
// 构造函数会自动创建对象,自动返回这个对象
// 我们只需要向里面添加内容就可以了
function CreateObj(name, age) {
// 1.1 自动创建对象
var obj = {}

// 1.2 手动向对象里面添加属性
// 当下面使用 new 去创建对象的时候
// 这里的 this 指向当前实例(new 前面的变量)
this.name = name
this.age = age
this.sayHi = function () { console.log('hello world') }

// 1.3 自动返回对象
// 不用输入return语句
}

// 2.使用自定义后的函数去创建对象
// 构造函数在使用的时候,需要和 new 关键字连用
// 如果不连用,那么没有意义

// 第一次调用 createObj 的时候,和 new 关键字连用了
// 我们 createObj 里面的 this 指向了 new 前面的变量 obj1
// 函数内部的代码在执行的时候,就是向 obj1 添加了 name age 和 sayHi 三个成员
var obj1 = new createObj('Jack', 18)

// 第二次调用 createObj 的时候,和 new 关键字连用了
// 我们 createObj 里面的 this 指向了 new 前面的变量 obj2
// 函数内部的代码在执行的时候,就是向 obj2 添加了 name age 和 sayHi 三个成员
var obj2 = new createObj('Rose', 20)

console.log(obj1, obj2)

构造函数的首字母习惯上大写(这里的构造函数是CreateObj),用来区分于普通函数,内部使用的this对象,来指向即将要生成的实例对象,使用New关键字来联用生成实例对象。

通过上面代码比较,我们会发现工厂模式创建了一个空对象obj,并且返回了这个对象,但是构造函数没有这一步,那是因为用new关键字实例化对象已经帮我们做了以下操作:

  1. 创建一个空对象 obj;
  2. 将新创建的空对象的隐式原型指向其构造函数的显示原型。
  3. 使用 call 改变 this 的指向
  4. 如果无返回值或者返回一个非对象值,则将 obj 返回作为新对象;如果返回值是一个……

后两种方法的异同

关于工厂函数创建对象自定义构造函数创建对象

共同点
都是函数,都可以创建对象,都可以传入参数

不同点

  • 工厂模式:

    1. 函数名是小写
    2. 有new
    3. 有返回值
    4. new之后的对象是当前的对象
    5. 直接调用函数就可以创建对象
  • 自定义构造函数:

    1. 函数名是大写(首字母)
    2. 没有new
    3. 没有返回值
    4. this是当前的对象
    5. 通过new的方式来创建对象

三、构造函数的使用

视频讲解

四、构造函数的不合理

视频讲解

五、原型prototype

视频讲解

每个函数都有函数原型prototype,只要向要构造的函数的原型上写一些方法,那么每一个该构造函数实例化后的对象都会使用原型上的方法,每一个实例都可以使用,并且用的都是同一个函数,不会出现浪费空间的行为。

1
2
3
4
5
6
7
8
9
10
function Person() {}
Person.prototype.sayHi = function () { console.log('我是Person原型上的方法') }
console.log(Person.prototype)

// 当创建Person这个构造函数的实例化对象 p1 的时候
// 访问 p1的 sayHi 成员,会发现是没有的
// 那么它自动会去Person的原型(prototype)上查找
var p1 = new Person()
console.(p1)
p1.sayHi()

六、简单版面向对象选项卡HTML

视频教程

  1. 抽象内容
  2. 书写构造函数

【原型和原型链】

1. 原型

视频教程

  1. 构造函数的不好
  2. 用原型来解决问题

每一个构造函数天生自带一个 prototype 属性,是一个对象数据类型

每一个实例对象天生自带一个属性 __proto__ ,指向所构造函数的 prototype

当访问对象的成员的时候,首先在自己身上查找,如果没有,自动去到 __proto__ 上查找

我们把需要设置给实例的方法,放在构造函数(prototype)上,所有用此构造函数创建出的实例都可以访问使用

2. 原型链

视频教程

  • 问题1:实例对象身上的 __proto__ 指向谁?
    => 指向所属构造函数的 prototype
    => p1所属的构造函数是 Person
    => 所以p1.__proto__指向 Person.prototype

  • 问题2:Person.prototype__proto__ 指向谁?
    => Person.prototype 所属构造函数是谁
    => 因为 Person.prototype 是一个对象数据类型(Object)
    => 在 JS内所有的 Object 数据类型都是属于 Object 这个内置的构造函数
    => Person.prototype 是属于 Object 这个内置构造函数的
    => Person.prototype 的 proto 指向 Object.prototype

  • 问题3:Person__proto__ 指向谁?
    =>
    =>
    =>

不想写了,看视频吧……【两手一摊】

原型链:
1. 用__proro__串联起来的对象链状结构
2. 注意:是使用 __proro__ 串联的那条才算
3. 每一个对象数据类型,都有一个属于自己的原型链
4. 作用:为了访问对象成员(先找自己有没有,再顺着链往上找__proro__
5. 一直往上找,直到 Object.protype 都没有要找的成员,那么返回 undefined


【ES6语法规则】

定义变量

除了之前的var关键字,又新增了两个。

  1. let:定义变量
  2. const:定义常量(特殊的变量)

varletconst区别如下:

  • var会进行预解析

    • letconst不会进行预解析
      在定义声明之前使用变量会报错
  • var可以声明两个重名的变量

    • letconst不能定义重名变量
      定义重名变量会报错
  • var没有块级作用域(是指一个可以执行代码段的{}都会限制该变量的适用范围)

    • letconst有块级作用域
      也就是说用它们定义的变量,出了花括号就不能用了

letconst区别如下:

  • let定义变量的时候可以不赋值

    • const在定义变量的时候必须赋值
  • let可以定义的变量可以被修改

    • const定义的变量一经赋值无法修改

总而言之:

  1. var的作用域更大;
  2. let的作用域小,除了出了花括号不能用之外,和var其实差不多;
  3. const的作用域小,除了出了花括号不能用之外,还是一次性的,不能改变其值;

箭头函数

是ES6在语法中对函数表达式的简写

对于声明式函数不能使用

在某些规则上又和以前的函数有些不一样

什么是函数表达式?
函数表达式,又叫做“匿名函数”
也就是我们不需要单独定义函数,就能直接进行赋值使用的那句代码

1
2
3
4
5
6
7
// 这些都叫函数表达式
xxx.onclick = function () {}
var obj = { fn: function () {} }
xxx.forEach(function () {})
setTimeout(function () {})
var fn = function () {}
...

箭头函数就是指,在我们书写函数表达式的时候,省略掉function关键字不写,在小括号和后面花括号之间加一个箭头=>,这就是箭头函数的语法

1
2
3
4
5
6
7
// 这些都叫函数表达式
xxx.onclick = () => {}
var obj = { fn: () => {} }
xxx.forEach(() => {})
setTimeout(() => {})
var fn = () => {}
...

箭头函数的特殊之处:

  • 某些情况下可以省略小括号()
    => 当你的形参只有一个的时候

    1
    2
    3
    4
    5
    6
    7
    //没有形参时,不能省
    var fn1 = () => { console.log('我没有形参') }

    //有形参时,能省小括号
    var fn2 = (a) => { console.log('我有一个形参',a) }
    //可以写成
    var fn2 = a => { console.log('我有一个形参,并省去了小括号',a) }
  • 某些情况下可以省略花括号{}
    => 当你的代码只有一句话的时候可以省略
    => 并且自动将这一句话的结果当做返回值

    1
    2
    3
    4
    5
    //代码只有一句话
    var fn1 = (a, b) => {
    return a + b
    }
    console.log(fn1(10, 20))
  • 箭头函数没有arguments

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    //普通函数里有`arguments
    var fn1 = function () {
    console.log(arguments)
    }
    fn1(100, 200, 300)

    //箭头函数里没有`arguments
    var fn1 = () => {
    console.log(arguments)
    }
    fn1(100, 200, 300)
  • 箭头函数内没有this
    => 箭头函数的 this 就是外部作用域的 this

    1
    2
    3
    4
    5
    6
    7
    var obj = {
    fn1: function () { console.log(this) },
    fn2: () => { console.log(this) }
    }

    obj.fn1() //因为 fn1 函数被 obj 调用,所以 this 是 obj
    obj.fn2() //因为是箭头函数,内部没有 this ,就是外部作用域的 this

函数参数默认值

  1. 函数在定义的时候,可以直接给形参设置一个默认值
  2. 当没有使用实参的时候,就使用默认值
  3. 当传递了实参,就使用传递的实参
  4. 普通函数可以使用,箭头函数也可以使用
1
2
3
4
5
6
7
// 设置参数 a 的默认值为100
function fn(a = 100) {
console.log(a)
}

fn() // => 100
fn(200) // => 200

解构赋值

  • 快速从 对象 或者 数组 中获取成员

  • 1: 数组的解构赋值:快速从数组中获取数据

1
2
3
4
//以前
let arr = ['hello', 'world']
let a = arr[0]
let a = arr[1]
1
2
3
4
// 数组的解构赋值(用中括号[])
let [a, b] = ['hello', 'world']
console.log(a) // => 'hello'
console.log(b) // => 'world'
  • 2: 对象的解构赋值:快速从对象中获取数据
1
2
3
4
5
6
7
8
//以前
let obj = {
name: 'Jack',
age : 18
}

let name = obj.name
let age = obj.age
1
2
3
4
5
6
7
8
9
10
// 对象的解构赋值(用花括号{})
let obj = { name: 'Jack', age : 18 }

// let{name} = obj
// let{age } = obj
//表示定义一个叫做name、age的变量,获取的是 obj 内叫做name、age成员的值
let{name, age} = obj

console.log(name)
console.log(age)
1
2
3
4
5
6
7
// 表示定义一个变量a,获取的是 obj 内叫做 a 的成员的值
// var { a } = obj
// console.log(a)

// 表示定义一个变量a,从 obj 内获取一个叫做 age 的值
var { age: a } = obj // 等价于 var a = obj.age
console.log

模板字符串

就是 ES6 内新增的定义字符串的方式

1
2
3
4
5
6
// 以前
var str = '内容'
var str = "内容"

// 现在
var str = `内容`

区别:

  1. 反引号中内容可以换行
  2. 可以直接在字符串内解析变量
    1
    2
    3
    4
    5
    6
    7
    //当需要解析变量的时候,直接
    ${ 变量 }

    //比如
    var age = 3
    var s1 = `我是百里飞洋,今年 ${age} 岁了`
    console.log(s1)

展开运算符

符号:...
作用:展开数组的中括号[],或者展开对象的大括号{}

1
2
3
4
5
6
7
8
// 1. 打印四个数
console.log(100, 200, 300, 400)

var arr = [100, 200, 300, 400]
// 2. 打印四个数组成的数组
console.log(arr)
// 3. 把数组展开后再打印(其实和上面第一种打印效果相同)
console.log(...arr)

有哪些应用?

  • 作用1:合并数组

    1
    2
    3
    4
    5
    6
    var arr1 = [10, 20]
    var arr2 = [30, 40]
    var arr3 = [50, 60, 70]
    var arr4 = [80, 90]
    // 合并数组
    var arr5 = [...arr1, ...arr2, ...arr3, ...arr4]
  • 作用2:给函数传递参数

    1
    2
    3
    4
    5
    6
    7
    var arr1 = [ 10, 20, 17, 7, 31, 22, 12 ]
    //传统方式
    var max = Math.max(10, 20, 17, 7, 31, 22, 12)
    console.log(max)
    //使用展开运算符的方式
    var max = Math.max(...arr)
    console.log(max)
  • 作用3:复制对象

    1
    2
    3
    4
    5
    6
    7
    8
    var obj = { name: 'Jack', age: 18 }
    var obj2 = {
    gender: '男',
    ...obj
    //相当于在这里插入了 name: 'Jack', age: 18 这两个成员
    //注意:当有相同成员的时候,后面的会覆盖前面的,注意顺序问题
    }
    console.log(obj2)

类语法

就是用 ES6 的语法书写构造函数,语法格式如下:

1
2
3
4
5
6
class 类名 {
// 原先ES5内的函数构造体
constructor () {}

// 直接书写原型上的方法即可
}
  • 原来构造函数的写法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // 1.构造函数
    function Person(name, age) {
    this.name = name
    this.age = age
    }
    // 2.原型上添加方法(给实例使用)
    Person.prototype.sayHi = function () { console.log('hello world') }

    // 3.用法:新建一个对象
    var p1 = new Person('Jack', 18)
    console.log(p1) //打印对象
    p1.sayHi() //执行原型上的方法

    可以不和 new 关键字连用,不报错但不规范。

  • 类语法构造函数的写法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    // 1.类的书写
    class Person {
    constructor (name, age) {
    // 这里按照ES5的构造函数体书写
    this.name = name
    this.age = age
    }

    // 2.直接书写原型上的方法即可
    sayHi () { console.log('你好 世界') }
    }

    // 3.用法:新建一个对象(还是一样的)
    var p1 = new Person('张三', 18)
    console.log(p1) //打印对象
    p1.sayHi() //执行原型上的方法

    类语法新建对象时必须和 new 关键字连用,否则会报错。

  • 原来书写 静态属性 和 静态方法 的方法

    1
    2
    3
    4
    5
    6
    7
    //静态属性
    Person.a = 100
    //静态方法
    Person.go = function() {console.log('跑起来')}

    console.log(Person.a)
    Person.go()
  • 类语法书写 静态属性 和 静态方法 的方法(需要加上一个static关键字)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    class Person {
    constructor (name, age) {
    this.name = name
    this.age = age
    }
    sayHi () { console.log('你好 世界') }

    //静态属性
    static a = 100
    //静态方法
    static go () { console.log('running') }
    }

    var p1 = new Person('张三', 18)
    console.log(p1) //打印对象
    p1.sayHi() //执行原型上的方法

特别感谢: