对象高级
一.Object构造函数模式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>01_Object构造函数模式</title>
</head>
<body>
<!--
方式一: Object构造函数模式
* 套路: 先创建空Object对象, 再动态添加属性/方法
* 适用场景: 起始时不确定对象内部数据
* 问题: 语句太多
-->
<script type="text/javascript">
var p = new Object()
p = {}
p.name = 'Tom'
p.age = 12
p.setName = function (name) {
this.name = name
}
console.log(p.name, p.age)
p.setName('Bob')
console.log(p.name, p.age)
</script>
</body>
</html>
二.对象字面量
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>02_对象字面量</title>
</head>
<body>
<!--
方式二: 对象字面量模式
* 套路: 使用{}创建对象, 同时指定属性/方法
* 适用场景: 起始时对象内部数据是确定的
* 问题: 如果创建多个对象, 有重复代码
-->
<script type="text/javascript">
var p = {
name: 'Tom',
age: 12,
setName: function (name) {
this.name = name
}
}
console.log(p.name, p.age)
p.setName('JACK')
console.log(p.name, p.age)
var p2 = {
name: 'Bob',
age: 13,
setName: function (name) {
this.name = name
}
}
</script>
</body>
</html>
三.工厂模式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>03_工厂模式</title>
</head>
<body>
<!--
方式三: 工厂模式
* 套路: 通过工厂函数动态创建对象并返回
* 适用场景: 需要创建多个对象
* 问题: 对象没有一个具体的类型, 都是Object类型
-->
<script type="text/javascript">
function createPerson(name, age) {
var obj = {
name: name,
age: age,
setName: function (name) {
this.name = name
}
}
return obj
}
var p1 = createPerson('Tom', 12)
var p2 = createPerson('Bob', 13)
function createStudent(name, price) {
var obj = {
name: name,
price: price
}
return obj
}
var s = createStudent('张三', 12000)
</script>
</body>
</html>
四.自定义构造函数模式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>04_自定义构造函数模式</title>
</head>
<body>
<!--
方式四: 自定义构造函数模式
* 套路: 自定义构造函数, 通过new创建对象
* 适用场景: 需要创建多个类型确定的对象
* 问题: 每个对象都有相同的数据, 浪费内存
-->
<script type="text/javascript">
function Person(name, age) {
this.name = name
this.age = age
this.setName = function (name) {
this.name = name
}
}
var p1 = new Person('Tom', 12)
p1.setName('Jack')
console.log(p1.name, p1.age)
console.log(p1 instanceof Person)
function Student (name, price) {
this.name = name
this.price = price
}
var s = new Student('Bob', 13000)
console.log(s instanceof Student)
var p2 = new Person('JACK', 23)
console.log(p1, p2)
</script>
</body>
</html>
五.构造函数+原型的组合模式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>05_构造函数+原型的组合模式</title>
</head>
<body>
<!--
方式六: 构造函数+原型的组合模式
* 套路: 自定义构造函数, 属性在函数中初始化, 方法添加到原型上
* 适用场景: 需要创建多个类型确定的对象
-->
<script type="text/javascript">
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.setName = function (name) {
this.name = name
}
var p1 = new Person('Tom', 23)
var p2 = new Person('Jack', 24)
console.log(p1, p2)
</script>
</body>
</html>
六.原型链继承
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>01_原型链继承</title>
</head>
<body>
<!--
方式1: 原型链继承
1. 套路
1. 定义父类型构造函数
2. 给父类型的原型添加方法
3. 定义子类型的构造函数
4. 创建父类型的对象赋值给子类型的原型
5. 将子类型原型的构造属性设置为子类型
6. 给子类型原型添加方法
7. 创建子类型的对象: 可以调用父类型的方法
2. 关键
1. 子类型的原型为父类型的一个实例对象
-->
<script type="text/javascript">
function Supper() {
this.supProp = 'Supper property'
}
Supper.prototype.showSupperProp = function () {
console.log(this.supProp)
}
function Sub() {
this.subProp = 'Sub property'
}
Sub.prototype = new Supper()
Sub.prototype.constructor = Sub
Sub.prototype.showSubProp = function () {
console.log(this.subProp)
}
var sub = new Sub()
sub.showSupperProp()
sub.showSubProp()
console.log(sub)
</script>
</body>
</html>
七.借用构造函数继承
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>02_借用构造函数继承</title>
</head>
<body>
<!--
方式2: 借用构造函数继承(假的)
1. 套路:
1. 定义父类型构造函数
2. 定义子类型构造函数
3. 在子类型构造函数中调用父类型构造
2. 关键:
1. 在子类型构造函数中通用call()调用父类型构造函数
-->
<script type="text/javascript">
function Person(name, age) {
this.name = name
this.age = age
}
function Student(name, age, price) {
Person.call(this, name, age)
this.price = price
}
var s = new Student('Tom', 20, 14000)
console.log(s.name, s.age, s.price)
</script>
</body>
</html>
八.组合继承
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>03_组合继承</title>
</head>
<body>
<!--
方式3: 原型链+借用构造函数的组合继承
1. 利用原型链实现对父类型对象的方法继承
2. 利用super()借用父类型构建函数初始化相同属性
-->
<script type="text/javascript">
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.setName = function (name) {
this.name = name
}
function Student(name, age, price) {
Person.call(this, name, age)
this.price = price
}
Student.prototype = new Person()
Student.prototype.constructor = Student
Student.prototype.setPrice = function (price) {
this.price = price
}
var s = new Student('Tom', 24, 15000)
s.setName('Bob')
s.setPrice(16000)
console.log(s.name, s.age, s.price)
</script>
</body>
</html>
九.进程与线程
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>01_进程与线程</title>
</head>
<body>
<!--
1. 进程:程序的一次执行, 它占有一片独有的内存空间
2. 线程: CPU的基本调度单位, 是程序执行的一个完整流程
3. 进程与线程
* 一个进程中一般至少有一个运行的线程: 主线程
* 一个进程中也可以同时运行多个线程, 我们会说程序是多线程运行的
* 一个进程内的数据可以供其中的多个线程直接共享
* 多个进程之间的数据是不能直接共享的
4. 浏览器运行是单进程还是多进程?
* 有的是单进程
* firefox
* 老版IE
* 有的是多进程
* chrome
* 新版IE
5. 如何查看浏览器是否是多进程运行的呢?
* 任务管理器==>进程
6. 浏览器运行是单线程还是多线程?
* 都是多线程运行的
-->
</body>
</html>
十.浏览器内核
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>02_浏览器内核</title>
</head>
<body>
<!--
1. 什么是浏览器内核?
* 支持浏览器运行的最核心的程序
2. 不同的浏览器可能不太一样
* Chrome, Safari: webkit
* firefox: Gecko
* IE: Trident
* 360,搜狗等国内浏览器: Trident + webkit
3. 内核由很多模块组成
* html,css文档解析模块 : 负责页面文本的解析
* dom/css模块 : 负责dom/css在内存中的相关处理
* 布局和渲染模块 : 负责页面的布局和效果的绘制
* 布局和渲染模块 : 负责页面的布局和效果的绘制
* 定时器模块 : 负责定时器的管理
* 网络请求模块 : 负责服务器请求(常规/Ajax)
* 事件响应模块 : 负责事件的管理
-->
</body>
</html>
十一.定时器引发的思考
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>03_定时器引发的思考</title>
</head>
<body>
<button id="btn">启动定时器</button>
<!--
1. 定时器真是定时执行的吗?
* 定时器并不能保证真正定时执行
* 一般会延迟一丁点(可以接受), 也有可能延迟很长时间(不能接受)
2. 定时器回调函数是在分线程执行的吗?
* 在主线程执行的, js是单线程的
3. 定时器是如何实现的?
* 事件循环模型(后面讲)
-->
<script type="text/javascript">
document.getElementById('btn').onclick = function () {
var start = Date.now()
console.log('启动定时器前...')
setTimeout(function () {
console.log('定时器执行了', Date.now()-start)
}, 200)
console.log('启动定时器后...')
for (var i = 0; i < 1000000000; i++) {
}
}
</script>
</body>
</html>
十二.JS是单线程的
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>04_JS是单线程的</title>
</head>
<body>
<!--
1. 如何证明js执行是单线程的?
* setTimeout()的回调函数是在主线程执行的
* 定时器回调函数只有在运行栈中的代码全部执行完后才有可能执行
2. 为什么js要用单线程模式, 而不用多线程模式?
* JavaScript的单线程,与它的用途有关。
* 作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。
* 这决定了它只能是单线程,否则会带来很复杂的同步问题
3. 代码的分类:
* 初始化代码
* 回调代码
4. js引擎执行代码的基本流程
* 先执行初始化代码: 包含一些特别的代码 回调函数(异步执行)
* 设置定时器
* 绑定事件监听
* 发送ajax请求
* 后面在某个时刻才会执行回调代码
-->
<script type="text/javascript">
setTimeout(function () {
console.log('timeout 2222')
alert('22222222')
}, 2000)
setTimeout(function () {
console.log('timeout 1111')
alert('1111111')
}, 1000)
setTimeout(function () {
console.log('timeout() 00000')
}, 0)
function fn() {
console.log('fn()')
}
fn()
console.log('alert()之前')
alert('------')
console.log('alert()之后')
</script>
</body>
</html>
十三.web_workers测试
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>06_Web Workers_测试</title>
</head>
<body>
<!--
1. H5规范提供了js分线程的实现, 取名为: Web Workers
2. 相关API
* Worker: 构造函数, 加载分线程执行的js文件
* Worker.prototype.onmessage: 用于接收另一个线程的回调函数
* Worker.prototype.postMessage: 向另一个线程发送消息
3. 不足
* worker内代码不能操作DOM(更新UI)
* 不能跨域加载JS
* 不是每个浏览器都支持这个新特性
-->
<input type="text" placeholder="数值" id="number">
<button id="btn">计算</button>
<script type="text/javascript">
function fibonacci(n) {
return n<=2 ? 1 : fibonacci(n-1) + fibonacci(n-2)
}
var input = document.getElementById('number')
document.getElementById('btn').onclick = function () {
var number = input.value
var result = fibonacci(number)
alert(result)
}
</script>
</body>
</html>
十四.web_workers测试2
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>06_Web Workers_测试</title>
</head>
<body>
<!--
1. H5规范提供了js分线程的实现, 取名为: Web Workers
2. 相关API
* Worker: 构造函数, 加载分线程执行的js文件
* Worker.prototype.onmessage: 用于接收另一个线程的回调函数
* Worker.prototype.postMessage: 向另一个线程发送消息
3. 不足
* worker内代码不能操作DOM(更新UI)
* 不能跨域加载JS
* 不是每个浏览器都支持这个新特性
-->
<input type="text" placeholder="数值" id="number">
<button id="btn">计算</button>
<script type="text/javascript">
var input = document.getElementById('number')
document.getElementById('btn').onclick = function () {
var number = input.value
var worker = new Worker('worker.js')
worker.onmessage = function (event) {
console.log('主线程接收分线程返回的数据: '+event.data)
alert(event.data)
}
worker.postMessage(number)
console.log('主线程向分线程发送数据: '+number)
}
</script>
</body>
</html>
十五.worker.js
function fibonacci(n) {
return n<=2 ? 1 : fibonacci(n-1) + fibonacci(n-2)
}
console.log(this)
this.onmessage = function (event) {
var number = event.data
console.log('分线程接收到主线程发送的数据: '+number)
var result = fibonacci(number)
postMessage(result)
console.log('分线程向主线程返回数据: '+result)
}
十六.分号问题
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>01_分号问题</title>
</head>
<body>
<!--
1. js一条语句的后面可以不加分号
2. 是否加分号是编码风格问题, 没有应该不应该,只有你自己喜欢不喜欢
3. 在下面2种情况下不加分号会有问题
* 小括号开头的前一条语句
* 中方括号开头的前一条语句
4. 解决办法: 在行首加分号
5. 强有力的例子: vue.js库
6. 知乎热议: https://www.zhihu.com/question/20298345
-->
<script type="text/javascript">
var a = 3
;(function () {
})()
var b = 4
;[1, 3].forEach(function () {
})
</script>
</body>
</html>
十七.设置
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script type="text/javascript">
console.log(3)
var arr = [1, 3]
for (var i = 0; i < arr.length; i++) {
var item = arr[i]
}
var fn = function test () {
}
</script>
</body>
</html>
十八.内存溢出与内存泄漏
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>02_内存溢出与内存泄露</title>
</head>
<body>
<!--
1. 内存溢出
* 一种程序运行出现的错误
* 当程序运行需要的内存超过了剩余的内存时, 就出抛出内存溢出的错误
2. 内存泄露
* 占用的内存没有及时释放
* 内存泄露积累多了就容易导致内存溢出
* 常见的内存泄露:
* 意外的全局变量
* 没有及时清理的计时器或回调函数
* 闭包
-->
<script type="text/javascript">
var obj = {}
for (var i = 0; i < 10000; i++) {
obj[i] = new Array(10000000)
console.log('-----')
}
function fn() {
a = new Array(10000000)
console.log(a)
}
fn()
var intervalId = setInterval(function () {
console.log('----')
}, 1000)
function fn1() {
var a = 4
function fn2() {
console.log(++a)
}
return fn2
}
var f = fn1()
f()
</script>
</body>
</html>