复习
第三阶段主题: 利用JS
来操作浏览器
-
前提: 学会JS
-
JS的v8引擎提供智能化 自动处理 – 自动修正错误的代码
-
类型隐式转换: 理论上同数据类型的值才能运算; JS会自动把不同类型转同类型
-
声明提升: 理论上必须 先声明 再使用 —
正常人书写代码的规范
-
一旦先使用再声明 也没事: JS引擎会帮你修改代码的顺序, 然后再执行
-
-
-
作用域
- 全局: 浏览器提供的全局对象 是
window
, 存放所有系统的api- 全局污染: 在脚本中声明的变量会存储在window里, 造成自定义变量 污染全局
- 局部: 函数
运行时
临时
产生的对象, 保存函数中声明的变量- 利用局部作用域可以保存
私有
的属性, 独立于全局之外 – 有效避免冲突
- 利用局部作用域可以保存
- 全局: 浏览器提供的全局对象 是
-
作用域链: 当函数中使用一个变量时, 按照
就近原则
从最近的作用域中获取 -
闭包: 对函数/局部作用域 在特殊场景中的称呼
-
如果一个
A
函数作用域中的变量 被其他B
函数使用, 则这个A作用域会被保存到B函数的scopes属性里, 目的是 防止释放, 导致B函数运行错误 -
利用闭包: 可以为函数提供私有的 对象属性
var 函数 = (function(){ var 变量 = 值 return function (){ 使用 变量... } })()
-
-
arguments
- 系统提供的关键词, 用于保存函数收到的所有
实参
- 应用:
函数重载
- 通过判断实参的个数或类型不同, 做不同的逻辑操作
- 系统提供的关键词, 用于保存函数收到的所有
-
this
- 代表函数
运行时
所在的对象 - 应用: 可以把
函数
放到对象
里执行 - call:
短暂访问
- 把函数临时放到对象中执行, 执行后从对象里立刻删除
- 代表函数
对象是引用类型
构造函数
原型机制
call
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<title>call 短暂访问 09:22</title>
</head>
<body>
<!-- call: 函数的一个属性, 提供了短暂访问对象的功能 -->
<!-- 把函数放到参数对象里, 运行一次, 再删除 -->
<!-- 语法: 函数.call(对象) -->
<script>
var r1 = { length: 20, width: 30 }
function area() {
console.log(this.length * this.width)
}
// 复杂方案: 手动
r1.area = area //先存入对象
r1.area() // 调用: 函数的this指向所在对象 r1
delete r1.area //用完清理
// 函数提供call属性: 自动完成上述任务
area.call(r1)
console.log(r1)
//
var emp = {
ename: '亮亮',
salary: 20000, //薪资
}
function total(yue) {
console.log(this.salary * yue)
}
// call(要放入的对象, 实参们...)
total.call(emp, 12)
// 计算 n月薪资 + 奖金
function bonus(yue, bonus) {
console.log(this.salary * yue + bonus)
}
// 计算出: 6个月总薪资 + 40000奖金
bonus.call(emp, 6, 40000)
</script>
</body>
</html>
apply
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<title>函数的apply 09:44</title>
</head>
<body>
<script>
// apply的作用 与 call 完全相同
var r1 = { length: 20, width: 30 }
function area() {
console.log(this.length * this.width)
}
area.call(r1)
area.apply(r1)
// 体积
function volume(height) {
console.log(this.length * this.width * height)
}
// 计算 高度100 时的体积
volume.call(r1, 100) //访问对象, 携带实参100
// 区别:
// call: 的实参 `散装`的, 要1个1个传递
// apply: 的实参 `打包/礼盒装`的, 放在数组里一起传
volume.apply(r1, [100])
//练习:
function suibian(x, y) {
console.log(this.length + this.width + x + y)
}
// 分别用 call 和apply 调用, 实参是 200 和 300
suibian.call(r1, 200, 300)
suibian.apply(r1, [200, 300])
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<title>apply 10:16</title>
</head>
<body>
<script>
// apply的应用场景
function max() {
var m = arguments[0]
for (var i = 0; i < arguments.length; i++) {
var value = arguments[i]
if (value > m) m = value
}
return m
}
var m = max(12, 3, 43, 546, 65)
console.log(m)
// 求出此数组的最大值
var nums = [12, 54, 56, 67, 87, 3]
// apply: 可以把数组拆包, 作为1个1个参数传递
// var m = max(nums)
// 参数1: 代表要放入的对象,作为函数中的this
// 但是: max函数体中没有使用this关键词, 所以参数1的值随意, 但是必须要写一个值, 来占位
var m = max.apply(0, nums)
console.log(m)
// Math有一个min 求最小值
var m = Math.min(12, 4, 45, 56, 67, 78, 7)
console.log(m)
// 练习: 用min求数组nums里的最小值
var nums = [12, 54, 56, 67, 87, 3]
var m = Math.min.apply(1, nums)
console.log(m)
// ... :展开符, 把数组的内容展开, 变为1个1个的参数
var m = Math.min(...nums)
console.log(m)
</script>
</body>
</html>
bind
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<title>bind 10:44</title>
</head>
<body>
<!-- onclick: 当点击时, 触发 -->
<button onclick="bind_area()">点我!</button>
<!-- 另一种语法 -->
<button onclick="area.call(r1, 20, 30)">点我</button>
<script>
// bind: 捆绑 - 把参数和对象 与函数捆绑在一起, 生成一个新的函数
var r1 = { length: 20, width: 30 }
function area(x, y) {
console.log(this.length + this.width + x + y)
}
var bind_area = area.bind(r1, 20, 30)
console.dir(bind_area)
// BoundThis: 捆绑到函数的对象
// BoundArgs: 捆绑到函数的实参
// 特点: 绑定完毕后 但是没有执行
// 适合延时执行的场景
</script>
</body>
</html>
对象引用类型
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<title>object 11:13</title>
</head>
<body>
<script>
// 对象类型: 引用传递
var emp1 = { ename: '泡泡', age: 18 }
var emp2 = emp1
emp2.age = 40
console.log(emp1.age) // 40
// 基础数据类型: 值传递
var a = 10
var b = a
a = 15
console.log(b) // 10
</script>
</body>
</html>
构造函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<title>构造函数 11:24</title>
</head>
<body>
<script>
// 构造函数: 用于 构建创造 对象的函数, 称为构造函数
// 所有的数据本质都是构造函数创建的, 只是作者为常用的数据设置了语法糖 -- 称为 字面量语法
var obj = {}
console.log(obj)
var x = new Object()
console.log(x)
var a = [11, 22, 33]
var b = new Array(11, 22, 33)
console.log(a)
console.log(b)
function c(x, y) {
console.log(x + y)
}
c(10, 20)
// 构造语法
// 最后的形参是函数体, 其他参数是形参名
var d = new Function('x', 'y', 'console.log(x + y)')
d(10, 30)
console.dir(d)
// 日期
// 不是所有构造函数都有语法糖, 只有常见的一些作者才提供了
var e = new Date()
console.log(e)
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<title>自定义构造函数 11:37</title>
</head>
<body>
<script>
// 构造函数相当于是一个工厂, 可以生产产品
// 制作一个函数Rect, 触发后可以生成 矩形对象
// 命名规范: 大驼峰命名法 - 首字母大写
// 从外观: 让程序员可以轻松识别出 是 构造函数
function Rect(length, width) {
var x = {} //新建空对象
x.width = width //存储值 到指定属性名
x.length = length
return x //返回组合出来的对象
}
// 构造函数: 可以快速创建出 规范的矩形对象
var r1 = Rect(10, 20)
console.log('r1:', r1)
var r2 = Rect(100, 40)
console.log('r2:', r2)
</script>
</body>
</html>
练习
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<title>练习 11:50</title>
</head>
<body>
<script>
// 制作一个 Cube 函数, 制作立方体对象
function Cube(length, width, height) {
var x = {}
x.length = length
x.width = width
x.height = height
// 给 x 对象设置共享对象存在哪里
// __proto__: 固定的关键词, 称为原型链
x.__proto__ = Cube.prototype
// 问题: 每个立方体对象 计算面积的函数是相同的
// 为每个对象配备一个函数, 属于浪费资源
// 应该: 共用同一个函数即可
// 计算体积
// x.volume = function () {
// return this.length * this.width * this.height
// }
return x
}
// 所有函数都有一个prototype属性, 用于存放共享方法
// prototype: 称为原型
Cube.prototype.volume = function () {
return this.width * this.length * this.height
}
console.dir(Cube)
// 使用方式如下:
var c1 = Cube(10, 20, 30) //长, 宽, 高
console.log(c1) //{length:10, width:20, height:30}
console.log(c1.volume())
var c2 = Cube(5, 10, 3)
console.log(c2)
console.log(c2.volume())
// 技巧: 用360浏览器查看最好
// 因为360的内核是旧的, 可以看到没有美化前的对象
console.log(c1.volume == c2.volume)
// 构造函数不允许生产三无产品
// 必须为生产的对象, 通过原型链__proto__ 属性, 指定其`售后`由谁负责. 构造函数的prototype 原型属性
//
// 原型链机制: 当对象读取一个属性时, 如果本身没有, 则自动到 原型链 链接到的 对象中查找
console.log(c1.volume())
</script>
</body>
</html>
原型
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<title>原型 14:40</title>
</head>
<body>
<script>
// 制作 Rect 函数, 制作矩形对象, 要求拥有算面积和周长的方法
function Rect(length, width) {
var x = {}
x.length = length
x.width = width
x.__proto__ = Rect.prototype
return x
}
Rect.prototype.area = function () {
return this.width * this.length
}
Rect.prototype.zc = function () {
return (this.width + this.length) * 2
}
// 使用示例:
var r1 = Rect(20, 50) //长, 宽
console.log(r1) // {length:20, width:50}
console.log(r1.area()) //得到1000, 长x宽
console.log(r1.zc()) //得到周长 140 (长+宽)*2
</script>
</body>
</html>
练习
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<title>练习 15:14</title>
</head>
<body>
<script>
// 制作一个 圆形 Circle 构造函数
function Circle(radius) {
var x = {}
x.radius = radius
x.__proto__ = Circle.prototype
return x
}
Circle.prototype.dia = function () {
return this.radius * 2
}
Circle.prototype.area = function () {
return this.radius * this.radius * 3.14
}
Circle.prototype.zc = function () {
return this.radius * 3.14 * 2
}
// 使用方式如下:
var c1 = Circle(5) //半径
console.log(c1) // {radius: 5}
console.log(c1.dia()) // 10 直径=半径*2
console.log(c1.area()) // 面积 = 3.14*半径*半径
console.log(c1.zc()) // 周长 = 半径*3.14*2
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<title>练习 15:30</title>
</head>
<body>
<script>
// 制作 英雄构造函数 Hero
function Hero(name, skill_1, skill_2) {
// new: 此关键词放在函数前, 则会自动完成 3行代码
// var this = {}
this.name = name
this.skill_1 = skill_1
this.skill_2 = skill_2
// this.__proto__ = Hero.prototype
// return this
}
Hero.prototype.s1 = function () {
console.log(this.name + '释放' + this.skill_1)
}
Hero.prototype.s2 = function () {
console.log(this.name + '释放' + this.skill_2)
}
//使用示例:
// new: 此关键词 让构造函数中少写3行
const h1 = new Hero('孙尚香', '翻滚突袭', '红莲爆弹')
console.log(h1)
// {name:"孙尚香", skill_1:'翻滚突袭', skill_2:"红莲爆弹"}
h1.s1() // 打印出: 孙尚香 释放 翻滚突袭
h1.s2() // 打印出: 孙尚香 释放 红莲爆弹
</script>
</body>
</html>
new
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<title>new 15:56</title>
</head>
<body>
<script>
// 用new 配合 构造函数
function Rect(length, width) {
this.length = length
this.width = width
}
Rect.prototype.area = function () {
return this.width * this.length
}
// 使用示例
var r1 = new Rect(20, 40) //长, 宽
console.log(r1) //{length:20, width:40}
console.log(r1.area()) //800 面积=长x宽
</script>
</body>
</html>
严格模式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<title>严格模式 16:21</title>
</head>
<body>
<!-- 严格模式: 在2009年出版的 ES5, 即JS的第五个版本推出的特性 -- 提供更加多的报错, 辅助程序员书写出健康的代码 -->
<script>
// 使用严格模式: 书写如下字符串后, 其下方的JS代码将进入严格模式
// 严格模式下, 变量必须先声明 后使用
// 有效防止 写错变量名 导致全局污染的情况
'use strict'
var servername = 'localhost'
// 变量前没有前缀, 则默认是 window.
// alert('111')
// window.servename = 'www.xin666.vip'
// 对象.属性名 = 值; 如果属性名不存在会怎么样?? 会新增
// 导致: 变量名写错, 错误的在全局对象window中新增了此属性
// -- 全局污染!
servename = 'www.xin666.vip'
var obj = { name: '泡泡' }
obj.naem = '世宇'
console.log(obj)
console.log(window) //后台展开查找到上方变量
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<title>严格模式 16:36</title>
</head>
<body>
<script>
// 开启严格模式:
// 在严格模式下, 直接触发全局中的函数, 其this指向undefined
// 代替之前的window, 避免全局污染
'use strict'
function Rect(length, width) {
// new : 此关键词会改变 this的指向, 指向构造出的对象
// var this = {}
console.log('this:', this)
this.length = length
this.width = width
}
// 要求: 利用Rect制作一个 r1 对象, 长20, 宽50
// 忘记写new, 函数的this是window, 造成全局污染
var r1 = Rect(20, 50)
console.log(r1)
console.log(window)
// Rect()
// window.Rect()
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<title>严格模式 16:55</title>
</head>
<body>
<script>
// 严格模式 是2009年出品的 ES5 版本中新增的特性
// 通过更多的报错, 强制程序员写出健壮的代码
// 严格模式提供了很多很多功能, 刚才讲解的是 具有代表性的几个特征
// 推荐以后写JS代码 一定要开严格模式
// 后续学习的框架中, 都是默认开启严格
'use strict'
// 严格模式下提供了更多的报错
// 取消了 静默失败
var emp = { ename: '泡泡', age: 18 }
// freeze: 冻结, 不许动
Object.freeze(emp)
// 冻结emp后, 此对象的值无法修改
emp.age = 40
console.log(emp)
</script>
</body>
</html>
class语法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<title>class 17:22</title>
</head>
<body>
<script>
// 由于JS的 构造函数写法过于复杂;
// 在2015年6月的 ES6 - JS的第六个版本中
// 引入了来自java的class语法: 全自动完成原型的操作
// class: 称为 类
class Rect {
// 固定名称的函数 constructor
// 相当于之前的构造函数, 通过 new 类名() 触发
constructor(length, width) {
this.length = length
this.width = width
}
// 所有书写在这个{}中的函数,都会放在原型里
// 省略function关键词
area() {
return this.length * this.width
}
zc() {
return (this.length + this.width) * 2
}
}
console.dir(Rect) //查看 prototype
var r1 = new Rect(10, 20)
console.log(r1)
console.log(r1.area())
console.log(r1.zc())
</script>
</body>
</html>
练习
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<title>练习 17:39</title>
</head>
<body>
<script>
// 用class语法制作 Circle 构造函数, 圆形
class Circle {
constructor(radius) {
this.radius = radius
}
dia() {
return this.radius * 2
}
zc() {
return this.radius * 2 * 3.14
}
area() {
return this.radius * this.radius * 3.14
}
}
// 使用示例
var c1 = new Circle(10) //半径 radius
console.log(c1.dia()) //直径: 半径x2
console.log(c1.zc()) //周长: 半径x2*3.14
console.log(c1.area()) //面积: 半径*半径*3.14
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<title>练习 17:51</title>
</head>
<body>
<script>
class Hero {
constructor(name, skill_1, skill_2, skill_3) {
this.name = name
this.skill_1 = skill_1
this.skill_2 = skill_2
this.skill_3 = skill_3
}
s1() {
console.log(this.name + '释放' + this.skill_1)
}
s2() {
console.log(this.name + '释放' + this.skill_2)
}
s3() {
console.log(this.name + '释放' + this.skill_3)
}
}
const h1 = new Hero('孙尚香', '翻滚突袭', '红莲爆弹', '究极弩炮')
h1.s1()
h1.s2()
h1.s3()
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>练习</title>
</head>
<body>
<script>
class Cube {
constructor(length, width, height) {
this.length = length
this.width = width
this.height = height
}
volume() {
return this.length * this.width * this.height
}
}
var c1 = new Cube(10, 20, 30)
console.log(c1)
console.log(c1.volume())
</script>
</body>
</html>
总结
- 函数的this相关事项
- 函数放在哪个对象中执行, 就代表哪个对象
- call: 让函数
短暂拜访
对象 – 临时放到对象里执行, 然后移除 - apply : 也是临时运行, 实参是
打包/礼盒装
放在数组中传递- 允许把数组作为参数传递给 需要 1个1个参数的 函数
- 在
ES6
版本中, 使用...
代替
- bind: 把对象和实参
捆绑
在函数上, 返回一个新的函数- 特色: 延时触发, 适合绑定在 元素的事件上, 例如点击事件
- 构造函数: 用于构造对象类型的函数
- 原型prototype 存放共享函数
__proto__
原型链, 链接到 prototype- new: 简化构造函数的代码
- class语法: 更加简化构造函数语法
- 严格模式: 辅助程序员书写更加健康的代码
- 开启方式:
use strict
- 开启方式: