基本信息
模板列表
接口列表
基本信息
预填数据
注入接口
基本信息
输入数据
输出结果
版本控制系统VCS
(Version control system)
产品级的分支模型:
git是一个基于内容寻址的存储系统。基于文件内容,而不是基于文件。
安装
Windows: msysgit http://msysgit.github.io
Mac: brew install git
Ubuntu: apt-get install git
git config
用户配置:
git config --global user.name "Darcy"
git config --global user.name text.example.com
配置级别:
git init
初始化之后会出现一个.git/目录,下面存储着包括config文件在内的几乎所有git相关文件。
git status
跟踪:track
git add
添加文件内容到暂存区
,同时文件被跟踪
。
批量添加: git add .
添加当前目录所有文件
.gitignore
如果有不希望跟踪的文件,那么需要配置忽略文件。
仅作用于未跟踪的文件。
gitignore常见配置:github中的示例
git rm
从暂存区
删除文件。
git rm --cached
仅仅从暂存区删除
git rm
同时从暂存区和工作目录删除
git rm $(git ls-files --deleted)
删除所有被跟踪,但是在工作目录被删除的文件
git commit
提交。
git commit -m "initial commit"
git commit -a -m "initial commit"
直接提交
git log
提交历史记录。
git log
git log --oneline
只有7位hash和提交时输入的commit message
git log --color --graph --pretty=format:(此处省略2行)
更美观,且有分支链
上面的命令太长了,不可能每次都这样输入,因此需要配置别名alias
。
语法:git config --global alias.shortname <full command>
例子:git config --global alias.lg "log --color --graph --pretty=format:(此处省略2行)"
这样就可以用 git lg
来表示上面那行命令了。
别名其实也存储在gitcofig文件中
git diff
显示版本差异。
git diff
工作目录与暂存区的差异
git diff -cached[<reference>]
暂存区与某次提交的差异,默认是<HEAD>,<HEAD>指向当前的提交
git diff [<reference>]
工作目录与某次提交的差异
git checkout --<file>
撤销本地修改。
即:将工作内容从暂存区复制到工作目录。
git reset HEAD <file>
取消暂存。
即:将文件内容从上次提交复制到暂存区。
git checkout HEAD --<file>
撤销全部改动:取消暂存 + 撤销本地修改。
git branch
git branch <branch-name>
新建分支
git branch -d <branch-name>
删除指定分支
git branch -v
显示所有分支信息
git checkout
通过移动HEAD检出版本,可用于分支切换。
git checkout <branch-name>
切换分支
git checkout -b <branch-name>
新建一个分支并切换到新分支
git checkout -b <reference>
切换到其他引用对象,比如 commit id
或 标签
git checkout -
回到上一个分支(把HEAD移动到上一个分支)
git reset
将当前分支恢复到某个历史版本。以下三种模式的主要区别是内容是否会恢复到工作目录和暂存区。
git reset --mixed e33e42
--mixed是默认参数,不写也行,当前内容(即原来的提交)会被复制到暂存区
git reset --hard e33e42
--hard 时,当前内容(即原来的提交)会被复制到暂存区和工作目录
git reset --soft e33e42
--soft时,暂存区和工作目录都不会有任何改变,原来的提交变成了一个无索引的提交,有可能会被回收,可以用 git reflog
找回来
捷径:git reset HEAD^/HEAD~1/HEAD~n
HEAD的上一次提交,前第n次提交
reset
与 checkout
在操作分支与操作文件时的不同git stash
我们在git checkout
切换分支的时候,经常会被提示“当前有未提交的内容,请commit
或stash
”,而我们通常是写到一半不希望commit的,所以这时就需要git stash
。
作用是:保存目前的工作目录和暂存区状态,返回一个干净的工作空间。
git stash save 'push to stash area'
第一步:保存
git stash list
第二步:查看已有列表 会显示:stash@{0}: On master: push to stash area
git stash apply stash@{0}
第三步:把保存的内容恢复到工作目录
git stash drop stash@{0}
第四步:把对应的stash命令删除掉
git stash pop stash@{0}
捷径:第三步+第四步
git merge
假定当前在master
分支。
git merge next
合并 next 分支的内容到master分支
如有冲突,会是下面这样:
<<<<<<< HEAD
next
=======
origin/master
>>>>>>> origin/master
====上面指当前分支的提交,下面是要merge过来的分支的提交内容。
git rebase
修剪提交历史的基线,俗称“变基”。
git rebase master
不要在共有分支使用rebase。
git tag
标签,一个不变的别名。用于标记某次发布。指向一个commit对象。
git tag v0.1 e39d0b2
打完标签之后,可以直接使用标签名切换分支: git checkout v0.1
git push
提交本地历史到远程。
git remote
git remote add origin ~/git-server
添加一个远程仓库别名origin
git remote -v
查看远程仓库信息
git fetch
获取远程仓库的提交历史。
git fetch origin/master
git merge origin/master
git pull
=git fetch + git merge
git clone
获取一个远程仓库作为本地仓库。
git clone ~/git-server test2
会克隆远程仓库到 test2目录下
封装实现
暴露接口
声明依赖
math模块:
//math.js
function add(a, b) {
return a + b;
}
function sub(a, b) {
return a - b;
}
caculator模块:
//caculator.js
var action = "add";
function compute(a, b){
switch(action){
case "add": return add(a, b);
case "sub": return sub(a, b);
}
}
可以看出 caculator
模块是依赖math
模块的。
math
模块特点:无封装性:变量全部散落在全局里。
接口结构不明显:如果我们没有简化代码,那么并不能清楚的知道math
到底输出了哪些接口。
caculator
模块特点:没有依赖声明:依赖了math模块但是却没有声明。
使用全局状态:使用了action这个全局状态,应该尽量避免。
math模块:
//math.js
var math = {
add: function add(a, b) {
return a + b;
}
sub: function sub(a, b) {
return a - b;
}
}
caculator模块:
//caculator.js
var caculator = {
action: "add",
compute: function compute(a, b){
switch(action){
case "add": return add(a, b);
case "sub": return sub(a, b);
}
}
}
math
模块特点:结构性好:用字面量把接口进行了结构化。
访问控制差:依然没有进行控制。
caculator
模块特点:依然没有依赖声明:依赖了math模块但是却没有声明。
无法设置私有属性:action
虽然是成员属性,但在外部依然可以访问到。
IIFE
(Immediately-invoked Function Expression)解决无法设置私有属性
的问题。caculator模块:
//caculator.js
var caculator = (function(){
var action = "add";
return {
compute: function compute(a, b){
switch(action){
case "add":
return math.add(a, b);
case "sub":
return math.sub(a, b);
}
}
}
})();
caculator
模块特点:依然依然没有依赖声明:依赖了math模块但是却没有声明。
有了私有属性:action
是我们要的私有属性,compute
函数可以访问到,而且在caculator
外面无法访问到。
caculator模块:
//caculator.js
var caculator = (function(m){
var action = "add";
function compute(a, b){
switch(action){
case "add":
return m.add(a, b);
case "sub":
return m.sub(a, b);
}
}
return {
compute: conpute
}
})(math);
caculator
模块特点:显示了依赖声明:把math模块作为参数传了进去,并且可以对形参进行命名,这里命名为m
。
math模块仍然污染了全局变量。
必须手动进行依赖管理:math模块是手动传进去的,必须手动保证math是在这之前就被加载了。
注意return
的部分与原来不一样了:学名叫 揭露模块模式review module pattern
,优点是在暴露的模块进行增删查改的时候会非常方便。
帮助我们只暴露一个类似于namespace
的全局变量。而不是将math
这样的模块都注册在全局作用域中。
math模块:
//math.js
namespace("math", [], function(){
function add(a, b) {
return a + b;
}
function sub(a, b) {
return a - b;
}
return {
add: add,
sub: sub
}
})
//第一个参数为模块声明,第二个参数为依赖的模块,第三个参数为模块的构成
caculator模块:
//caculator.js
namespace("caculator", ["math"], function(m){
var action = "add";
function compute(a, b){
return m[action](a, b);
}
return {
compute: compute
}
}
依赖是统一注册在某个地方,而不是全局中的一个变量。
namespace的实现:
cache
中缓存了所有的模块。
实际返回的是createModule
这个函数,参数包括:模块名,依赖的模块,当前模块的实现。
如果只传入了一个参数,就返回这个模块cache[name]
。
取得所有依赖的模块deps
,即保证前面的模块都已经被定义好了,这样当前模块(这里为caculator
模块)才能运行。
最后初始化模并返回定义的模块cache[name]
。
不再污染全局环境:把模块都定义在一个namespace
变量中。
没有依赖管理:依然是我们手动进行依赖管理。
如果这些模块分散在不同的文件中,我们在用的时候就要对引入的脚本顺序进行手动排序。
比如 module2.js中依赖了module1.js,那么写的时候就要先写module.js,像这样:
<body>
<script src="module1.js"></script>
<script src="module2.js"></script>
</body>
但是我们在实际开发过程中的依赖总是很复杂。那是一条又长又复杂的依赖链。非要人肉分析是会抓狂的。而这其实是模块系统的工作。
依赖管理(加载 / 注入 / 分析 / 初始化)
决定模块写法
//main.js
function add(a, b){
return a + b;
}
function sub(a, b){
return a - b;
}
exports.add = add
exports.sub = sub
比原来的写法多了接口暴露:exports.add = add
exports.sub = sub
//caculator.js
var math = require("./math");
function Caculator(container){
//...
}
exports.Caculator = Caculator
比原来的写法多了依赖声明: var math = require("./math");
和 接口暴露:exports.Caculator = Caculator
。
优点:
运行时支持,模块定义非常简单:只是利用了几个全局变量exports, module, require
。
文件级别的模块作用域隔离:这几个全局变量的作用域都是文件级别的,虽然JS没有文件级别的作用域,但我们对它进行了封装,使得使用时一个文件有一个作用域,它们使用起来非常安全。
可以处理循环依赖。
缺点:
不是标准组织的规范。
同步的require,没有考虑浏览器环境。而我们的浏览器文件加载是一个异步的过程,这是最大的问题,这是否就意味着我们的浏览器没办法使用了呢?当然不是。现在有很多工具比如browserify
,比如webpack
,可以帮助我们把多个文件级别的模块打包成一个文件,这样我们引入单个文件就可以在浏览器里使用了。
因为CommonJS天然的不适合异步环境,所以出现了天然异步的AMD(Asynchronous Module Definition)
与我们前面的namespace非常像。
//main.js
define([], function(){
function add(a, b){
return a + b;
}
function sub(a, b){
return a - b;
}
return {
add: add,
sub: sub
}
})
比原来的写法多了包裹函数:define
,第一个参数为依赖的模块列表,第二个参数为当前模块的实现。
//caculator.js
define(["./math"], function(math){
function Caculator(container){
//...
}
return {
Caculator: Caculator
}
}
同时AMD还支持一个简单的CommonJS写法,只不过要用一层函数包裹起来define(function(require, exports){ ... })
。
优点:
专为异步I/O环境打造,适合浏览器环境。
支持类似CommonJS的书写方式。
通过插件支持可以加载非JS资源。
成熟的打包构建工具,并可结合插件实现一些预处理的工作。
缺点:
模块定义繁琐,需要额外的函数嵌套。
只是库级别的支持,需要引入额外的库,比如requireJS。
无法处理循环依赖。
无法实现条件加载,因为只是库级别的。
//main.js
function add(a, b){
return a + b;
}
function sub(a, b){
return a - b;
}
export { add, sub }
比原来的写法多了接口暴露:export {add, sub}
//caculator.js
import { math } from './math';
function Caculator(container){
//...
}
export { Caculator }
比原来的写法多了依赖声明: import { math } from './math';
和 接口暴露:export { Caculator }
。
优点:
真正官方的规范,未来的趋势。
语言级别的支持。
适应所有的JavaScript运行时环境,包括浏览器。
可以处理循环依赖。
针对特定问题的解答,就有专业性
不控制应用程序的流程
被动的被调用
比如,一个DatePicker时间选择器是一个库,一个Backbone.view是一个框架。
控制反转 Inverse of control <···主要区别
决定应用程序生命周期
一般会集成大量的库
下面这个图很好的解释了控制反转:
框架决定了什么时候调用库,什么时候要求你的代码去实现某些功能。
框架和库,他们都是解决方案。关于解决方案,分为7各方面:
DOM
communication 通信
Utility 工具库
Template 模板技术
Component 组件
Route 路由
Architecture MV*架构
jQuery
zepto.JS
Mootools
手势支持:Hammer.js
局部滚动:iScroll.js
高级动画:Velocity.js
视频播放:video.js
处理与服务器的请求与响应
预处理请求数据/响应数据 & Error/Success的判断封装
多种类型请求,统一接口
处理浏览器兼容性
jQuery
zepto.JS
Reqwest
qwest
以上都是异步的请求,但对于实时性要求非常高的产品比如im聊天工具,就需要立即响应。这时需要用websocket。推荐下面的库:
socket.io
提供JS原生不提供的功能
方法门面包装,使其易于使用。即shim(语言垫片),保证实现与规范一致。
异步队列 / 流程控制 比如promise
Bootstrap
Foundation
监听url变化,并通知注册的模块,进行页面切换
通过Javascript进行主动跳转
历史管理
对目标浏览器的兼容性的支持
提供一种范式帮助(强制)开发者进行模块解耦
试图与模型分离
更容易进行单元测试
更容易实现应用程序的扩展
各种框架比较的参考网站:
http://todomvc.com/
https://www.javascripting.com/
https://www.javascriptoo.com/
http://microjs.com/#
数据类型(每个页面的每个模块都要单独定义包含的数据类型列表)
模板资源
异步接口(请求方式,请求地址,输入参数,输出结果)
页面摘要
项目结构
初始代码
模拟数据
通用原件(logo,输入框,图标,按钮,翻页,复选框列表,loading)
通用列表(歌单。歌手,收藏的节目)
复合组件(比如评论)
浮层弹窗
一个组件(BannerSlifer)的栗子:
本地测试
异步测试
对接联调
打包发布
优化配置