}
let car = new Kuaiche(100, ‘桑塔纳’)
let trip = new Trip(car)
trip.start()
trip.end()
02
// 车
class Car {
constructor(num) {
this.num = num
}
}
// 入口摄像头
class Camera {
shot(car) {
return {
num: car.num,
inTime: Date.now()
}
}
}
// 出口显示器
class Screen {
show(car, inTime) {
console.log(‘车牌号’, car.num)
console.log(‘停车时间’, Date.now() - inTime)
}
}
// 停车场
class Park {
constructor(floors) {
this.floors = floors || []
this.camera = new Camera()
this.screen = new Screen()
this.carList = {}
} in (car) {
// 获取摄像头的信息:号码 时间
const info = this.camera.shot(car)
// 停到某个车位
const i = parseInt(Math.random() * 100 % 100)
const place = this.floors[0].places[i]
place.in()
info.place = place
// 记录信息
this.carList[car.num] = info
}
out(car) {
// 获取信息
const info = this.carList[car.num]
const place = info.place
place.out()
// 显示时间
this.screen.show(car, info.inTime)
// 删除信息存储
delete this.carList[car.num]
}
emptyNum() {
return this.floors.map(floor => {
return ${floor.index} 层还有 ${floor.emptyPlaceNum()} 个车位
}).join(‘\n’)
}
}
// 层
class Floor {
constructor(index, places) {
this.index = index
this.places = places || []
}
emptyPlaceNum() {
let num = 0
this.places.forEach(p => {
if (p.empty) {
num = num + 1
}
})
return num
}
}
// 车位
class Place {
constructor() {
this.empty = true
} in () {
this.empty = false
}
out() {
this.empty = true
}
}
// 测试代码------------------------------
// 初始化停车场
const floors = []
for (let i = 0; i < 3; i++) {
const places = []
for (let j = 0; j < 100; j++) {
places[j] = new Place()
}
floors[i] = new Floor(i + 1, places)
}
const park = new Park(floors)
// 初始化车辆
const car1 = new Car(‘A1’)
const car2 = new Car(‘A2’)
const car3 = new Car(‘A3’)
console.log(‘第一辆车进入’)
console.log(park.emptyNum())
park.in(car1)
console.log(‘第二辆车进入’)
console.log(park.emptyNum())
park.in(car2)
console.log(‘第一辆车离开’)
park.out(car1)
console.log(‘第二辆车离开’)
park.out(car2)
console.log(‘第三辆车进入’)
console.log(park.emptyNum())
park.in(car3)
console.log(‘第三辆车离开’)
park.out(car3)
工厂模式
-
介绍
-
UML && 代码演示
-
使用场景
介绍:
-
将 new 操作单独封装
-
遇到 new 时,就要考虑是否该用工厂模式
class Product {
constructor(name) {
this.name = name
}
init() {
}
fun1() {
}
}
class Creator {
create(name) {
return new Product(name)
}
}
// test
let creator = new Creator()
let p1 = creator.create(‘p1’)
p1.init()
场景:
-
jQuery:$(‘div’)
-
$(‘div’) 和 new $(‘div’) 有何区别(查看上述 jQuery 例子)
-
React.createElement
-
vue 异步组件
学习经典库的方法:
-
学习功能如何实现
-
学习实现思路?怎么设计的
-
强制自己写代码,模拟(刻意练习)
-
模仿练习(拿来主义)
设计原则验证:
-
构造函数和创建者分离
-
符合开放封闭原则
单例模式
介绍:
-
系统中被唯一使用的
-
一个类只有一个实例。
登陆框、购物车…
说明:
-
单例模式需要用到 java 的特性(private)
-
ES6 中没有(typescript 除外)
-
只能用 java 代码来演示 UML 图的内容
场景:
-
jquery 只有一个 $
-
模拟登陆框
-
购物车
-
vuex 和 redux 中的 store
jQuery
// jQuery 只有一个 $
if (window.jQuery != null) {
return window.jQuery
} else {
// init
}
class SingleObject {
login() {
console.log(‘login…’)
}
}
SingleObject.getInstance = (function() {
let instance
return function() {
if (!instance) {
instance = new SingleObject();
}
return instance
}
})()
// 测试
let obj1 = SingleObject.getInstance()
obj1.login()
let obj2 = SingleObject.getInstance()
obj2.login()
console.log(obj1 === obj2)
class LoginForm {
constructor() {
this.state = ‘hide’
}
show() {
if (this.state === ‘show’) {
console.log(‘已经显示’)
return
}
this.state = ‘show’
console.log(‘登录框已显示’)
}
hide() {
if (this.state === ‘hide’) {
console.log(‘已经隐藏’)
return
}
this.state = ‘hide’
console.log(‘登录框已隐藏’)
}
}
LoginForm.getInstance = (function() {
let instance
return function() {
if (!instance) {
instance = new LoginForm();
}
return instance
}
})()
// 一个页面中调用登录框
let login1 = LoginForm.getInstance()
login1.show()
// login1.hide()
// 另一个页面中调用登录框
let login2 = LoginForm.getInstance()
login2.show()
// 两者是否相等
console.log(‘login1 === login2’, login1 === login2)
设计原则验证:
-
符合单一职责原则,只实例化唯一的对象
-
没法具体开放封闭原则,但是绝对不违反开放封闭原则
适配器模式
插头,转接口…
介绍:
-
旧接口格式和使用者不兼容
-
中间加一个适配转换接口
UML类图:
演示:
class Adaptee {
specificRequest() {
return ‘德国标准插头’
}
}
class Target {
constructor() {
this.adaptee = new Adaptee()
}
request() {
let info = this.adaptee.specificRequest()
return ${info} - 转换器 - 中国标准插头
}
}
// 测试代码
let target = new Target()
let res = target.request()
console.log(res)
场景:
-
封装旧接口
-
vue computed
// 当前ajax封装
ajax({
url: ‘getData’,
type: ‘post’,
dataType: ‘json’,
data: {
id: “123”
}
}).done(function(){})
// 历史代码
// $.ajax({…})
// 做一层适配器
var $ = {
ajax: function(options) {
return ajax(options)
}
}
设计原则验证:
-
将旧接口和使用者进行分离
-
符合开放封闭原则
装饰器模式
介绍:
-
为对象添加新功能
-
不改变其原有的结构和功能
例子:手机壳
UML类图:
ES7 装饰器
babel插件:babel-plugin-transform-decorators-legacy
库:core-decorators(常用装饰器已经写好了,直接拿来用)
// 装饰类
// @testable
// class MyTestableClass {
// // …
// }
// function testable(target) {
// target.isTestable = true;
// }
// console.log(MyTestableClass.isTestable) // true
function mixins(…list) {
return function (target) {
Object.assign(target.prototype, …list)
}
}
const Foo = {
foo() { console.log(‘foo’) }
}
@mixins(Foo)
class MyClass {}
let obj = new MyClass();
obj.foo() // ‘foo’
// 装饰方法
function readonly(target, name, descriptor) {
// descriptor对象原来的值如下
// {
// value: specifiedFunction,
// enumerable: false,
// configurable: true,
// writable: true
// };
descriptor.writable = false;
return descriptor;
}
class Person {
constructor() {
this.first = ‘A’
this.last = ‘B’
}
@readonly
name() {
return ${this.first} ${this.last}
}
}
var p = new Person()
console.log(p.name())
p.name = function() {} // 这里会报错,因为 name 是只读属性
// another
function log(target, name, descriptor) {
var oldValue = descriptor.value;
descriptor.value = function() {
console.log(Calling ${name} with
, arguments);
return oldValue.apply(this, arguments);
};
return descriptor;
}
class Math {
@log
add(a, b) {
return a + b;
}
}
const math = new Math();
const result = math.add(2, 4);
console.log(‘result’, result);
// core-decorators
// import { readonly } from ‘core-decorators’
// class Person {
// @readonly
// name() {
// return ‘zhang’
// }
// }
// let p = new Person()
// console.log(p.name())
// // p.name = function () { /…/ } // 此处会报错
import { deprecate } from ‘core-decorators’;
class Person {
@deprecate
facepalm() {}
@deprecate(‘We stopped facepalming’)
facepalmHard() {}
@deprecate(‘We stopped facepalming’, { url: ‘http://knowyourmeme.com/memes/facepalm’ })
facepalmHarder() {}
}
let person = new Person();
person.facepalm();
// DEPRECATION Person#facepalm: This function will be removed in future versions.
person.facepalmHard();
// DEPRECATION Person#facepalmHard: We stopped facepalming
person.facepalmHarder();
// DEPRECATION Person#facepalmHarder: We stopped facepalming
//
// See http://knowyourmeme.com/memes/facepalm for more details.
设计原则验证:
-
将现有对象和装饰器进行分离,两者独立存在
-
符合开放封闭原则
代理模式
介绍:
-
使用者无权访问目标对象
-
中间加代理,通过代理做授权和控制
例子:
-
科学上网
-
明星经纪人
UML类图:
演示:
场景:
-
网页事件代理
-
jQuery $.proxy
-
ES6 Proxy
// 明星
let star = {
name: ‘张XX’,
age: 25,
phone: ‘13910733521’
}
// 经纪人
let agent = new Proxy(star, {
get: function(target, key) {
if (key === ‘phone’) {
// 返回经纪人自己的手机号
return ‘18611112222’
}
if (key === ‘price’) {
// 明星不报价,经纪人报价
return 120000
}
return target[key]
},
set: function(target, key, val) {
if (key === ‘customPrice’) {
if (val < 100000) {
// 最低 10w
throw new Error(‘价格太低’)
} else {
target[key] = val
return true
}
}
}
})
// 主办方
console.log(agent.name)
console.log(agent.age)
console.log(agent.phone)
console.log(agent.price)
// 想自己提供报价(砍价,或者高价争抢)
agent.customPrice = 150000
// agent.customPrice = 90000 // 报错:价格太低
console.log(‘customPrice’, agent.customPrice)
访问代理,接口地址是不会变的。
设计原则验证:
-
代理类和目标类分离,隔离开目标类和使用者
-
符合开放封闭原则
代理模式 VS 适配器模式
-
适配器模式:提供一个不同的接口
-
代理模式:提供一模一样的接口
代理模式 VS 装饰器模式
-
装饰器模式:扩展功能,原有功能不变且可直接使用
-
代理模式:显示原有功能,但是经过限制或者阉割之后的
外观模式
介绍:
-
为子系统中的一组接口提供了一个高层接口
-
使用者使用这个高层接口
观察者模式
介绍:
-
发布 & 订阅
-
一对多
UML类图:
例子:
- 点咖啡,点好后坐等被叫
// 主题,接收状态变化,触发每个观察者
class Subject {
constructor() {
this.state = 0
this.observers = []
}
getState() {
return this.state
}
setState(state) {
this.state = state
this.notifyAllObservers()
}
attach(observer) {
this.observers.push(observer)
}
notifyAllObservers() {
this.observers.forEach(observer => {
observer.update()
})
}
}
// 观察者,等待被触发
class Observer {
constructor(name, subject) {
this.name = name
this.subject = subject
this.subject.attach(this)
}
update() {
console.log(${this.name} update, state: ${this.subject.getState()}
)
}
}
// 测试代码
let s = new Subject()
let o1 = new Observer(‘o1’, s)
let o2 = new Observer(‘o2’, s)
let o3 = new Observer(‘o3’, s)
s.setState(1)
s.setState(2)
s.setState(3)
场景:
-
网页事件绑定
-
Promise
-
jQuery callbacks
-
nodeJs 自定义事件
// jquery callbacks
var callbacks = $.Callbacks() // 注意大小写
callbacks.add(function(info) {
console.log(‘fn1’, info)
})
callbacks.add(function(info) {
console.log(‘fn2’, info)
})
callbacks.add(function(info) {
console.log(‘fn3’, info)
})
callbacks.fire(‘gogogo’) // 发布
callbacks.fire(‘fire’)
// nodejs 自定义事件
const EventEmitter = require(‘events’).EventEmitter
const emitter1 = new EventEmitter()
emitter1.on(‘some’, () => {
// 监听 some 事件
console.log(‘some event is occured 1’)
})
emitter1.on(‘some’, () => {
// 监听 some 事件
console.log(‘some event is occured 2’)
})
// 触发 some 事件
emitter1.emit(‘some’)
const emitter = new EventEmitter()
emitter.on(‘sbowName’, name => {
console.log('event occured ', name)
})
emitter.emit(‘sbowName’, ‘zhangsan’) // emit 时候可以传递参数过去
// 任何构造函数都可以继承 EventEmitter 的方法 on emit
class Dog extends EventEmitter {
constructor(name) {
super()
this.name = name
}
}
var simon = new Dog(‘simon’)
simon.on(‘bark’, function() {
console.log(this.name, ’ barked’)
})
setInterval(() => {
simon.emit(‘bark’)
}, 500)
node Stream 用到了自定义事件:
// 文件太大,用流的形式读取
// 监听文件有多少字符
var fs = require(‘fs’)
var readStream = fs.createReadStream(‘./data/file1.txt’) // 读取文件的 Stream
var length = 0
readStream.on(‘data’, function(chunk) {
length += chunk.toString().length
})
readStream.on(‘end’, function() {
console.log(length)
})
// 监听一行一行的数据(监听文件有多少行)
var readline = require(‘readline’);
var fs = require(‘fs’)
var rl = readline.createInterface({
input: fs.createReadStream(‘./data/file1.txt’)
});
var lineNum = 0
rl.on(‘line’, function(line) {
lineNum++
});
rl.on(‘close’, function() {
console.log(‘lineNum’, lineNum)
});
其他场景:
-
nodeJs 中: 处理 http 请求;多进程通讯
-
vue 和 react 组件生命周期触发
-
vue watch
// node 处理 http 请求
var http = require(‘http’)
function serverCallback(req, res) {
var method = req.method.toLowerCase() // 获取请求的方法
if (method === ‘get’) {}
if (method === ‘post’) {
// 接收 post 请求的内容
var data = ‘’
req.on(‘data’, function(chunk) {
// “一点一点”接收内容
console.log(‘chunk’, chunk.toString())
data += chunk.toString()
})
req.on(‘end’, function() {
// 接收完毕,将内容输出
console.log(‘end’)
res.writeHead(200, { ‘Content-type’: ‘text/html’ })
res.write(data)
res.end()
})
}
}
http.createServer(serverCallback).listen(8081) // 注意端口别和其他 server 的冲突
console.log(‘监听 8081 端口……’)
设计原则验证:
-
主题和观察者分离,不是主动触发而是被动监听,两者解耦
-
符合开放封闭原则
迭代器模式
介绍:
-
顺序访问一个集合(有序集合)
-
使用者无需知道集合的内部结构(封装)
UML类图:
使用 jQuery 示例:
var arr = [1, 2, 3]
var nodeList = document.getElementsByTagName(‘p’)
var $p = $(‘p’)
// 要对这三个变量进行遍历,需要写三个遍历方法
// 第一
arr.forEach(function(item) {
console.log(item)
})
// 第二
var i, length = nodeList.length
for (i = 0; i < length; i++) {
console.log(nodeList[i])
}
// 第三
$p.each(function(key, p) {
console.log(key, p)
})
// 如何能写出一个方法来遍历这三个对象呢
function each(data) {
var $data = $(data) // 生成迭代器
$data.each(function(key, p) {
console.log(key, p)
})
}
each(arr)
each(nodeList)
each($p)
class Iterator {
constructor(conatiner) {
this.list = conatiner.list
this.index = 0
}
next() {
if (this.hasNext()) {
return this.list[this.index++]
}
return null
}
hasNext() {
if (this.index >= this.list.length) {
return false
}
return true
}
}
class Container {
constructor(list) {
this.list = list
}
getIterator() {
return new Iterator(this)
}
}
// 测试代码
let container = new Container([1, 2, 3, 4, 5])
let iterator = container.getIterator()
while (iterator.hasNext()) {
console.log(iterator.next())
}
使用场景:
-
JQuery each
-
ES6 Iterator
为何 ES6 Iterator 存在?
-
ES6 语法中,有序集合的数据类型已经很多
-
Array Map Set String TypedArray arguments NodeList
-
需要有一个统一的遍历接口来遍历所有数据类型
-
注意:object 不是有序集合,可以用 Map 代替
ES6 Iterator 是什么?
-
以上数据类型,都有 [Symbol.iterator] 属性
-
属性值是函数,执行函数返回一个迭代器
-
这个迭代器就有 next 方法可顺序迭代子元素
-
可运行 Array.prototype[Symbol.iterator] 来测试
ES6 Iterator 示例:
// 手动实现遍历器
function each(data) {
// 生成遍历器
let iterator = dataSymbol.iterator
// console.log(iterator.next()) // 有数据时返回 {value: 1, done: false}
// console.log(iterator.next())
// console.log(iterator.next())
// console.log(iterator.next())
// console.log(iterator.next()) // 没有数据时返回 {value: undefined, done: true}
let item = { done: false }
while (!item.done) {
item = iterator.next()
if (!item.done) {
console.log(item.value)
}
}
}
// 数组已经部署了 Iterator 接口
// for of 可以遍历 所有部署了 Iterator 接口的数据结构
function each(data) {
for (let item of data) {
console.log(item)
}
}
let arr = [1, 2, 3, 4]
let nodeList = document.getElementsByTagName(‘p’)
let m = new Map()
m.set(‘a’, 100)
m.set(‘b’, 200)
each(arr)
each(nodeList)
each(m)
ES6 Iterator 与 Generator
-
Iterator 的价值不限于上述几个类型的遍历
-
还有 Generator 函数的使用
-
即只要返回的数据符合 Iterator 接口要求
-
即可使用 Iterator 语法,这就是迭代器模式
// function* helloWorldGenerator() {
// yield ‘hello’;
// yield ‘world’;
// return ‘ending’;
// }
// var hw = helloWorldGenerator();
// console.log(hw.next())
// console.log(hw.next())
// console.log(hw.next())
// console.log(hw.next())
function* foo() {
yield 1;
yield 2;
yield 3;
yield 4;
yield 5;
return 6;
}
for (let v of foo()) {
console.log(v);
}
设计原则验证:
-
迭代器对象和目标对象分离
-
迭代器将使用者与目标对象分离开
-
符合开放封闭原则
状态模式
介绍:
-
一个对象有状态的变化
-
每次状态变化都会触发一个逻辑
-
不能总用 if…else 来控制
UML类图:
// 状态
class State {
constructor(color) {
this.color = color
}
handle(context) {
console.log(turn to ${this.color} light
)
context.setState(this)
}
}
// 主体
class Context {
constructor() {
this.state = null
}
setState(state) {
this.state = state
}
getState() {
return this.state
}
}
// 测试代码
let context = new Context()
let greed = new State(‘greed’)
let yellow = new State(‘yellow’)
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
3, 4]
let nodeList = document.getElementsByTagName(‘p’)
let m = new Map()
m.set(‘a’, 100)
m.set(‘b’, 200)
each(arr)
each(nodeList)
each(m)
ES6 Iterator 与 Generator
-
Iterator 的价值不限于上述几个类型的遍历
-
还有 Generator 函数的使用
-
即只要返回的数据符合 Iterator 接口要求
-
即可使用 Iterator 语法,这就是迭代器模式
// function* helloWorldGenerator() {
// yield ‘hello’;
// yield ‘world’;
// return ‘ending’;
// }
// var hw = helloWorldGenerator();
// console.log(hw.next())
// console.log(hw.next())
// console.log(hw.next())
// console.log(hw.next())
function* foo() {
yield 1;
yield 2;
yield 3;
yield 4;
yield 5;
return 6;
}
for (let v of foo()) {
console.log(v);
}
设计原则验证:
-
迭代器对象和目标对象分离
-
迭代器将使用者与目标对象分离开
-
符合开放封闭原则
状态模式
介绍:
-
一个对象有状态的变化
-
每次状态变化都会触发一个逻辑
-
不能总用 if…else 来控制
UML类图:
// 状态
class State {
constructor(color) {
this.color = color
}
handle(context) {
console.log(turn to ${this.color} light
)
context.setState(this)
}
}
// 主体
class Context {
constructor() {
this.state = null
}
setState(state) {
this.state = state
}
getState() {
return this.state
}
}
// 测试代码
let context = new Context()
let greed = new State(‘greed’)
let yellow = new State(‘yellow’)
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-oS0DxrxZ-1715548257829)]
[外链图片转存中…(img-ThNQ9cuA-1715548257829)]
[外链图片转存中…(img-BlQZ0Rfa-1715548257830)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!