MVC 的含义
- MVC 三个对象分别做什么
-
M 代表模型(model),用于封装与应用程序的业务逻辑相关的数据以及对数据的处理方法,会有一个或多个视图监听此模型。一旦模型的数据发生变化,模型将通知有关的视图。
-
V 代表视图(view),描绘的是 model 的当前状态,所有应该被用户看到的东西都属于 V。当模型的数据发生变化,视图相应地得到刷新自己的机会。
-
C 代表控制器(controller),定义用户界面对用户输入的响应方式,起到不同层面间的组织作用,用于控制应用程序的流程,它处理用户的行为和数据 model 上的改变。
-
- 根据 MVC 的理论,所有的程序,都可以分解为 M、V、C 三个对象。
eventBus
- 什么是 eventBus,它的作用是什么
- 个人理解,eventBus 可以自定义事件,可以通过自定义事件的监听和触发,来实现对象之间的通信,当数据或某些特性发生改变时,能自动监听事件作出一些改变。通过使用 jQuery 库来实现 eventBus 非常简单,jQuery 内部封装好了用于监听( on )和触发( trigger )事件的 API
- 比如,一个简单的用于加减乘除运算的代码:数据 data 改变后,对数据 data 进行渲染,调用到渲染函数 render()
add(){
data++;
render(data);
},
minus(){
data--;
render(data);
},
mul(){
data*=2;
render(data);
},
div(){
data/=2;
render(data);
},
复制代码
- 使用 eventBus 来简化后,只要 data 更新,就自动调用 render() 函数
const eventBus = $({})
const m = {
data: {
n: 100
},
updata(data) {
Object.assign(m.data, data)
eventBus.trigger('n:updataed')
}
}
const v = {
render() {}
}
const c = {
init() {
eventBus.on('n:updataed', () => {
v.render(m.data)
})
},
add() {
m.updata(m.data.n + 1)
},
minus() {
m.updata(m.data.n - 1)
},
multiply() {
m.updata(m.data.n * 2)
},
divide() {
m.updata(m.data.n / 2)
}
}
复制代码
表驱动编程
-
使用表驱动法,可以更优雅的写 if-else、switch-case
- 代码大全的解释:
表驱动法就是一种编程模式(scheme)——从表里面查找信息而不使用逻辑语句(if 和case)。事实上,凡是能通过逻辑语句来选择的事物,都可以通过查表来选择。对简单的情况而言,使用逻辑语句更为容易和直白。但随着逻辑链的越来越复杂,查表法也就愈发显得更具吸引力。
-
比如获取当前日期:
const date = new Date()
const day = date.getDay()
if (day === 0) {
console.log('今天是周日')
} else if (day === 1) {
console.log('今天是周一')
}
...
else{
console.log('今天是周六')
}
复制代码
使用 if…else 或者 switch 要写七次。如果把数据保存在一个数组里,代码则会简洁的多:
const week = ['星期日', '星期一', '星期二', ...]
const date = new Date()
const day = date.getDay()
const today = week[day]
复制代码
- 表驱动编程的意义在于逻辑与数据的分离。
比如依据分数来进行等级评定:
function level(score){
if (score < 60) {
return '差'
} else if(score < 80) {
return '良'
} else if(score < 99) {
return '优'
}
}
复制代码
这种简单的代码可以用,但是一旦需要添加一个或多个等级,比如添加 60 ~ 70 或者满分的等级,就需要修改逻辑。
使用表驱动:
function level(score) {
const levelTabel = {
60: '差',
80: '良',
90: '优',
100: '完美'
}
const key = Object.keys(levelTable)
const len = key.length
for (let i in levelTable) {
if (parseFloat(score) <= i) {
return levelTable[i]
}
}
return levelTable[key[len - 1]]
}
复制代码
就算要添加再多等级,也只需要简单添加数据表,而不用再修改逻辑。
JS 模块化开发
以下文章摘录自: 链接
-
模块化是一个语言发展的必经之路,其能够帮助开发者拆分和组织代码,随着前端技术的发展,前端编写的代码量也越来越大,就需要对代码有很好的管理,而模块化能够帮助开发者解决命名冲突、管理依赖、提高代码的可读性、代码解耦以及提高代码的复用性。
- 模块化开发其实就是封装细节,提供使用接口,彼此之间互不影响,每个模块都是实现某一特定的功能,同时也需要避免全局变量的污染,最初通过函数实现模块,实际上是利用了函数的局部作用域来形成模块
function fn1(){} function fn2(){} 复制代码
- 上述的 fn1 与 fn2 函数分别形成了两个模块,需要使用的时候直接调用即可,但是这样无法保证不与其他模块发生变量名冲突,而且模块成员之间看不出直接关系,再之后便有使用对象作为模块,将成员的都放置于对象中。
var nameModule={ name:0, fn1:function(){}, fn2:function(){} } 复制代码
- 在模块化规范形成之前,开发者通常使用 Module 设计模式来解决 Js 全局作用域的污染问题。Module 模式最初被定义为一种在传统软件工程中为类提供私有和公有封装的方法,在 JavaScript 中,Module 模式使用匿名函数自调用构建闭包来封装,通过自定义暴露行为来区分私有成员和公有成员。
var nameModule = (function() { var moduleName = "module"; // 私有属性 function setModuleName(name) { moduleName = name; } function getModuleName() { return moduleName; } return { setModuleName: setModuleName, getModuleName: getModuleName } })(); console.log(nameModule.getModuleName()); // module nameModule.setModuleName("nameModule"); console.log(nameModule.getModuleName()); // nameModule 复制代码
-
CommonJs、AMD、CMD、ES6 都是用于模块化定义中使用的规范,其为了规范化模块的引入与处理模块之间的依赖关系以及解决命名冲突问题,并使用模块化方案来使复杂系统分解为代码结构更合理,可维护性更高的可管理的模块。
-
ES6 在语言标准的层面上实现了模块的功能,是为了成为浏览器和服务器通用的模块解决方案,ES6 标准使用 export 与 export default 来导出模块,使用 import 导入模块。此外在浏览器环境中是可以使用 require 来导入 export、export default 导出的模块的,但依然建议使用 import 标准导入模块。目前 ES6 模块是静态的,无法实现按需加载,当然可以使用 babel 进行解析,也可以使用 CommonJS 的 require,此外有一份新的规范提案也有可能将动态加载并入标准。export、export default 主要有以下区别:
- export 能按需导入,export default 不行。
- export 可以有多个,export default 仅有一个。
- export 能直接导出变量表达式,export default 不行。
- export 方式导出,在导入时要加 {},export default 则不需要。
// 导出单个特性
export let name1, name2, …, nameN; // also var, const
export let name1 = …, name2 = …, …, nameN; // also var, const
export function FunctionName(){...}
export class ClassName {...}
// 导出列表
export { name1, name2, …, nameN };
// 重命名导出
export { variable1 as name1, variable2 as name2, …, nameN };
// 解构导出并重命名
export const { name1, name2: bar } = o;
// 默认导出
export default expression;
export default function (…) { … } // also class, function*
export default function name1(…) { … } // also class, function*
export { name1 as default, … };
// 导出模块合集
export * from …; // does not set the default export
export * as name1 from …; // Draft ECMAScript® 2O21
export { name1, name2, …, nameN } from …;
export { import1 as name1, import2 as name2, …, nameN } from …;
export { default } from …;
复制代码
// name-从将要导入模块中收到的导出值的名称
// member, memberN-从导出模块,导入指定名称的多个成员
// defaultMember-从导出模块,导入默认导出成员
// alias, aliasN-别名,对指定导入成员进行的重命名
// module-name-要导入的模块。是一个文件名
// as-重命名导入成员名称(“标识符”)
// from-从已经存在的模块、脚本文件等导入
import defaultMember from "module-name";
import * as name from "module-name";
import { member } from "module-name";
import { member as alias } from "module-name";
import { member1 , member2 } from "module-name";
import { member1 , member2 as alias2 , [...] } from "module-name";
import defaultMember, { member [ , [...] ] } from "module-name";
import defaultMember, * as name from "module-name";
import "module-name"; // 将运行模块中的全局代码, 但实际上不导入任何值。
复制代码
// 1.js
var a = 1;
var b = function(){
console.log(a);
}
var c = 3;
var d = a + c;
var obj = { a,b,c }
export {a,b};
export {c,d};
export default obj;
复制代码
<!-- 3.html 由于浏览器限制,需要启动一个server服务 -->
<!DOCTYPE html>
<html>
<head>
<title>ES6</title>
</head>
<body>
</body>
<script type="module">
import {a,b} from "./1.js"; // 导入export
import m1 from "./1.js"; // 不加{}即导入export default
import {c} from "./1.js"; // 导入export 按需导入
console.log(a); // 1
console.log(b); // ƒ (){ console.log(a); }
console.log(m1); // {a: 1, c: 3, b: ƒ}
console.log(c); // 3
</script>
</html>
复制代码