divlab / divlab.github.io Goto Github PK
View Code? Open in Web Editor NEWHome Page: https://divlab.github.io/
Home Page: https://divlab.github.io/
我的理解
给最大宽度max定基数,例如100px(也可以是任意值,常见的是:设计稿/10 ),如果小了, 到底小多少呢,client/max * 100px 这就是html font-size
当计算的时候 w/这个基数(rem) =x,也即是 x*基数 rem 为真实的设计稿的width
使用的时候 设计稿/得出值,想问为什么?因为xrem X得出值,就是真实的渲染尺寸
1.原npm地址
npm config set registry http://registry.npmjs.org
2.设置国内镜像
a.通过config命令
npm config set registry https://registry.npm.taobao.org
npm info underscore (如果上面配置正确这个命令会有字符串response)
b.命令行指定
npm --registry https://registry.npm.taobao.org info underscore
c.编辑 ~/.npmrc 加入下面内容
registry = https://registry.npm.taobao.org
3.使用nrm管理registry地址
a.下载nrm
npm install -g nrm
b.添加registry地址
nrm add npm http://registry.npmjs.org
nrm add taobao https://registry.npm.taobao.org
c.切换npm registry地址
nrm use taobao
nrm use npm
对称加密:通信双方使用相同的密钥进行加密。特点是加密速度快,但是缺点是需要保护好密钥,如果密钥泄露的话,那么加密就会被别人破解。常见的对称加密有 AES,DES 算法。
非对称加密:它需要生成两个密钥:公钥(Public Key)和私钥(Private Key)。
公钥顾名思义是公开的,任何人都可以获得,而私钥是私人保管的,相信大多程序员已经对这种算法很熟悉了。
我们提交代码到 Github 的时候,就可以使用 SSH key:在本地生成私钥和公钥,私钥放在本地 .ssh 目录中,公钥放在 Github 网站上。
这样每次提交代码,不用麻烦的输入用户名和密码了,Github 会根据网站上存储的公钥来识别我们的身份。公钥负责加密,私钥负责解密;或者,私钥负责加密,公钥负责解密。
这种加密算法安全性更高,但是计算量相比对称加密大很多,加密和解密都很慢。
常见的非对称算法有 RSA。SSL/TLS 是利用了对称加密和非对称加密的特点。
用git在本地新建一个分支后,需要做远程分支关联。如果没有关联,git会在下面的操作中提示你显示的添加关联。
关联目的是在执行git pull, git push操作时就不需要指定对应的远程分支,你只要没有显示指定,git pull的时候,就会提示你。
git branch --set-upstream-to=origin/remote_branch your_branch
其中,origin/remote_branch是你本地分支对应的远程分支;your_branch是你当前的本地分支。
Git 2.0版本之前,默认采用matching方法,现在改为默认采用simple方式。
simple方式:如果当前分支只有一个追踪分支,那么git push origin到主机时,可以省略主机名。
matching方式:如果当前分支与多个主机存在追踪关系,那么git push --set-upstream origin master(省略形式为:git push -u origin master)将本地的master分支推送到origin主机(--set-upstream选项会指定一个默认主机),同时指定该主机为默认主机,后面使用可以不加任何参数使用git push。
原因:
1.可能是因为当前版本小于2.0
2.若不是版本问题则是因为当前分支与多个主机存在对应关系,而当前未指定对应关系
此时检查一下项目下.git的.config文件中是否缺少该分支指定信息
解决:
1.按照提示在命令行中输入git push --set-upstream origin dev
FETCH_HEAD //当前节点 git pull 同步
任何一个版本控制系统中,最有用的特性之一莫过于 “撤销(undo)”操作。在Git中,“撤销”有很多种含义。
当你完成了一次新的提交(commit),Git会及时存储当前时刻仓库(repository)的快照(snapshot);你能够使用Git将项目回退到任何之前的版本。
下文中,我将列举几个常见的、需要“撤销”的场景,并且展示如何使用Git来完成这些操作。
一、撤销一个公共修改 Undo a "public" change
场景:你刚刚用git push将本地修改推送到了GitHub,这时你意识到在提交中有一个错误。你想撤销这次提交。
使用撤销命令:git revert
发生了什么:git revert将根据给定SHA的相反值,创建一个新的提交。如果旧提交是“matter”,那么新的提交就是“anti-matter”——旧提交中所有已移除的东西将会被添加进到新提交中,旧提交中增加的东西将在新提交中移除。
这是Git最安全、也是最简单的“撤销”场景,因为这样不会修改历史记录——你现在可以git push下刚刚revert之后的提交来纠正错误了。
二、修改最近一次的提交信息 Fix the last commit message
场景:你只是在最后的提交信息中敲错了字,比如你敲了git commit -m "Fxies bug #42",而在执行git push之前你已经意识到你应该敲"Fixes bug #42"。
使用撤销命令:git commit –amend或git commit --amend -m "Fixes bug #42"
发生了什么:git commit –amend将使用一个包含了刚刚错误提交所有变更的新提交,来更新并替换这个错误提交。由于没有staged的提交,所以实际上这个提交只是重写了先前的提交信息。
三、撤销本地更改 Undo "local" changes
场景:当你的猫爬过键盘时,你正在编辑的文件恰好被保存了,你的编辑器也恰在此时崩溃了。此时你并没有提交过代码。你期望撤销这个文件中的所有修改——将这个文件回退到上次提交的状态。
使用撤销命令:git checkout --
发生了什么:git checkout将工作目录(working directory)里的文件修改成先前Git已知的状态。你可以提供一个期待回退分支的名字或者一个确切的SHA码,Git也会默认检出HEAD——即:当前分支的上一次提交。
注意:用这种方法“撤销”的修改都将真正的消失。它们永远不会被提交。因此Git不能恢复它们。此时,一定要明确自己在做什么!(或许可以用git diff来确定)
四、重置本地修改 Reset "local" changes
场景:你已经在本地做了一些提交(还没push),但所有的东西都糟糕透了,你想撤销最近的三次提交——就像它们从没发生过一样。
使用撤销命令:git reset或git reset --hard
发生了什么:git reset将你的仓库纪录一直回退到指定的最后一个SHA代表的提交,那些提交就像从未发生过一样。默认情况下,git reset会保留工作目录(working directory)。这些提交虽然消失了,但是内容还在磁盘上。这是最安全的做法,但通常情况是:你想使用一个命令来“撤销”所有提交和本地修改——那么请使用--hard参数吧。
五、撤销本地后重做 Redo after undo "local"
场景:你已经提交了一些内容,并使用git reset –hard撤销了这些更改(见上面),突然意识到:你想还原这些修改!
使用撤销命令:git reflog和git reset, 或者git checkout
发生了什么:git reflog是一个用来恢复项目历史记录的好办法。你可以通过git reflog恢复几乎任何已提交的内容。
你或许对git log命令比较熟悉,它能显示提交列表。git reflog与之类似,只不过git reflog显示的是HEAD变更次数的列表。
一些说明:
只有HEAD会改变。当你切换分支时,用git commit提交变更时,或是用git reset撤销提交时,HEAD都会改变。但当你用git checkout --时, HEAD不会发生改变。(就像上文提到的情形,那些更改根本就没有提交,因此reflog就不能帮助我们进行恢复了)
git reflog不会永远存在。Git将会定期清理那些“不可达(unreachable)”的对象。不要期望能够在reflog里找到数月前的提交记录。
reflog只是你个人的。你不能用你的reflog来恢复其他开发者未push的提交。
因此,怎样合理使用reflog来找回之前“未完成”的提交呢?这要看你究竟要做什么:
如果你想恢复项目历史到某次提交,那请使用git reset --hard
如果你想在工作目录(working direcotry)中恢复某次提交中的一个或多个文件,并且不改变提交历史,那请使用git checkout--
如果你想确切的回滚到某次提交,那么请使用git cherry-pick。
六、与分支有关的那些事 Once more, with branching
场景:你提交了一些变更,然后你意识到你正在master分支上,但你期望的是在feature分支上执行这些提交。
使用撤销命令:git branch feature, git reset --hard origin/master, 和 git checkout feature
发生了什么:你可能用的是git checkout -b来建立新的分支,这是创建和检出分支的便捷方法——但实际你并不想立刻切换分支。git branch feature会建立一个叫feature的分支,这个分支指向你最近的提交,但是你还停留在master分支上。
git reset --hard将master回退至origin/master,并忽略所有新提交。别担心,那些提交都还保留在feature上。
最后,git checkout将分支切换到feature,这个分支原封不动的保留了你最近的所有工作。
七、事半功倍处理分支 Branch in time saves nine
场景:你基于master新建了一个feature分支,但是master分支远远落后与origin/master。现在master分支与origin/master同步了,你期望此刻能在feature下立刻commit代码,并且不是在远远落后master的情况下。
使用撤销命令:git checkout feature和git rebase master
发生了什么:你也许已经敲了命令:git reset(但是没用--hard,有意在磁盘上保存这些提交内容),然后敲了git checkout -b,之后重新提交更改,但是那样的话,你将失去本地的提交记录。不过,一个更好的方法:
使用git rebase master可以做到一些事情:
1.首先,它定位你当前检出分支和master之间的共同祖先节点(common ancestor)。
2.然后,它将当前检出的分支重置到祖先节点(ancestor),并将后来所有的提交都暂存起来。
3.最后,它将当前检出分支推进至master末尾,同时在master最后一次提交之后,再次提交那些在暂存区的变更。
八、批量撤销/找回 Mass undo/redo
场景:你开始朝一个既定目标开发功能,但是中途你感觉用另一个方法更好。你已经有十几个提交,但是你只想要其中的某几个,其他的都可以删除不要。
使用撤销命令:git rebase -i
发生了什么:-i将rebases设置为“交互模式(interactive mode)”。rebase开始执行的操作就像上文讨论的一样,但是在重新执行某个提交时,它会暂停下来,让你修改每一次提交。
rebase –i将会打开你的默认文本编辑器,然后列出正在执行的提交,就像这样:
前两列最关键:第一列是选择命令,它会根据第二列中的SHA码选择相应的提交。默认情况下,rebase –i会认为每个更改都正通过pick命令被提交。
要撤销一个提交,直接在编辑器删除对应的行就可以了。如果在你的项目不再需要这些错误的提交,你可以直接删除上图中的第1行和3-4行。
如果你想保留提交但修改提交信息,你可以使用reword命令。即,将命令关键字pick换成reword(或者r)。你现在可能想立刻修改提交消息,但这么做不会生效——rebase –i将忽略SHA列后的所有东西。现有的提交信息会帮助我们记住0835fe2代表什么。当你敲完rebase –i命令后,Git才开始提示你重写那些新提交消息。
如果你需要将2个提交合并,你可以用squash或者fixup命令,如下图:
squash和fixup都是“向上”结合的——那些用了这些合并命令(编者按:指squash、fixup)的提交,将会和它之前的提交合并:上图中,0835fe2和6943e85将会合并成一个提交,而38f5e4e和af67f82将会合并成另一个提交。
当你用squash时,Git将会提示是否填写新的提交消息;fixup则会给出列表中第一个提交的提交信息。在上图中,af67f82是一个“Ooops”信息,因为这个提交信息已经同38f5e4e一样了。但是你可以为0835fe2和6943e85合并的新提交编写提交信息。
当你保存并退出编辑器时,Git将会按照从上到下的顺序执行你的提交。你可以在保存这些提交之前,修改提交的执行顺序。如果有需要,你可以将af67f82和0835fe2合并,并且可以这样排序:
九、修复早先的提交 Fix an earlier commit
场景:之前的提交里落下了一个文件,如果先前的提交能有你留下的东西就好了。你还没有push,并且这个提交也不是最近的提交,因此你不能用commit –amend。
使用撤销命令:git commit --squash和git rebase --autosquash -i
发生了什么:git commit –squash将会创建一个新的提交,该提交信息可能像这样“squash! Earlier commit”。(你也可以手写这些提交信息,commit –squash只是省得让你打字了)。
如果你不想为合并的提交编写信息,也可以考虑使用命令git commit --fixup。这种情况下,你可能会使用commit --fixup,因为你仅希望在rebase中使用之前的提交信息。
rebase --autosquash –i将会启动rebase交互编辑器,编辑器会列出任何已完成的squash!和fixup!提交,如下图:
当使用--squash和–fixup时,你或许记不清你想修复的某个提交的SHA码——只知道它可能在一个或五个提交之前。你或许可以使用Git的^和操作符手动找回。HEAD^表示HEAD的前一次提交。HEAD4表示HEAD前的4次提交,加起来总共是前5次提交。
十、停止跟踪一个已被跟踪的文件 Stop tracking a tracked file
场景:你意外将application.log添加到仓库中,现在你每次运行程序,Git都提示application.log中有unstaged的提交。你在.gitignore中写上”*.log”,但仍旧没用——怎样告诉Git“撤销”跟踪这个文件的变化呢?
使用撤销命令:git rm --cached application.log
发生了什么:尽管.gitignore阻止Git跟踪文件的变化,甚至是之前没被跟踪的文件是否存在,但是,一旦文件被add或者commit,Git会开始持续跟踪这个文件的变化。类似的,如果你用git add –f来“强制”add,或者覆盖.gitignore,Git还是会继续监视变化。所以以后最好不要使用–f来add .gitignore文件。
如果你希望移除那些应当被忽略的文件,git rm –cached可以帮助你,并将这些文件保留在磁盘上。因为这个文件现在被忽略了,你将不会在git status中看到它,也不会再把这个文件commit了。
所有npm模块都有name,有的模块的name还有scope。scope的命名规则和name差不多,同样不能有url非法字符或者下划线点符号开头。scope在模块name中使用时,以@开头,后边跟一个/ 。package.json中,name的写法如下:
"name": "@somescope/somepackagename"
scope是一种把相关的模块组织到一起的一种方式,也会在某些地方影响npm对模块的处理。npm公共仓库支持带有scope的的模块,同时npm客户端对没有scope的模块也是向后兼容的,所以可以同时使用两者。
安装带有scope的模块
带有scope的模块安装在一个子目录中,如果正常的模块安装在node_modules/packagename目录下,那么带有scope的模块安装在node_modules/@myorg/packagename目录下,@myorg就是scope前面加上了@符号,一个scope中可以包含很多个模块。
npm install @myorg/mypackage
在package.json中写明一个依赖:
"dependencies": {
"@myorg/mypackage": "^1.3.0"
}
如果@符号被省略,那么npm会尝试从github中安装模块,在npm install命令的文档中有说明
https://docs.npmjs.com/cli/install
使用带有scope的模块
在代码中require一个含有scope的模块:
require(‘@myorg/mypackage’)
nodejs在解析socpe模块的时候,并没有把它当做一个有什么蹊跷的东西来处理,仅仅是按照路径去找@myorg目录下的mypackage模块。
发布带有scope的模块
带有scope的模块可以被发布到任意支持socpe模块的npm仓库,包括npm公共仓库,公共仓库从2015-04-19就开始支持带有scope的模块了。
如果有必要,可以把某个scope关联到某个仓库,见下面的说明。
如果要发布一个公共socpe模块,你必须在最开始发布的时候指定–access public。这样会让模块能被公开使用,就像在publish之后运行了 npm access public命令一样。
如果要发布私有模块,那么你必须有一个npm私有模块账户,可以选择自己搭建一个npm服务,或者直接使用官方的。发布私有模块的命令:
npm publish
npm publish –access restricted
即发布socpe模块时,默认就是restricted的。这些在npm publish文档里边可以看到详细说明。 https://docs.npmjs.com/cli/publish
将一个scope和一个仓库关联
scope可以和一些自己搞的npm仓库关联起来。这样你就可以同时使用npm公共仓库和一些其他的私有仓库中的模块,例如企业npm。可以用npm login把scope关联到一个仓库:
npm login –registry=http://reg.example.com –scope=@myco
scope和仓库可以是一个多对一的关系:一个仓库里边可以放多个scope,但是一个scope同时只能放在一个仓库中。也可以用npm config把scope关联到一个仓库:
npm config set @myco:registry http://reg.example.com
当一个scope关联到一个私有仓库之后,该scope下的模块在npm install的时候都会从它关联的仓库中获取模块,而不是npm配置的仓库,发布的时候也是同样的道理,会发布到它关联的仓库而不是npm配置的仓库。
作者:wavesnow
链接:https://www.jianshu.com/p/ac5b5f65320b
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
在一些博客系统,如掘金的博客中,可以复制代码,它是如何实现的
它一般可以使用第三方库 clipboard-copy 来实现,源码很简单,可以读一读
长按识别二维码查看原文
https://github.com/feross/clipboard-copy/blob/master/index.js
标题:clipboard-copy
目前最为推荐的方式是使用 Clipboard API 进行实现
navigator.clipboard.writeText(text)
而对于一些不支持 Clipboard API 的浏览器,使用以下 API 进行复制
选中: Selection API
复制: document.execCommand (已被废弃)
选中: Selection API/Range API
选中主要利用了 Selection API 与 Range API
长按识别二维码查看原文
https://developer.mozilla.org/en-US/docs/Web/API/Selection
标题:Selection API
图片
选中的代码如下
const selection = window.getSelection();
const range = document.createRange();
// RangeAPI: 制造区域
range.selectNodeContents(element);
// Selection: 选中区域
selection.addRange(range);
selectedText = selection.toString();
取消选中的代码如下
window.getSelection().removeAllRanges();
它有现成的第三方库可以使用: select.js
长按识别二维码查看原文
https://github.com/zenorocha/select
标题:select.js
图片
复制: execCommand
复制就比较简单了,execCommand
document.execCommand('copy')
想要查看自己本机的ssh到底是多少
输入下面的命令就可以:
cat .ssh/id_rsa.pub
1
查看完ssh还想复制ssh内容,一个简单的命令就可以搞定,
这个命令是可以复制本机的ssh到剪切板中,在其他地方com+v就可以粘贴ssh了
cat .ssh/id_rsa.pub | pbcopy
————————————————
版权声明:本文为CSDN博主「smile&$」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/smile_68/article/details/112470696
解决方案:
core-js版本太高***
给它安装cnpm install core-js@2
ssh-keygen -t rsa -b 4096 -C "邮箱":这条命令的目的是为了让本地机器ssh登录远程机器上的GitHub账户无需输入密码。将这条命令分解:
1、ssh-keygen:
SSH 为 Secure Shell 的缩写,SSH 为建立在应用层基础上的安全协议。SSH 是目前较可靠,专为远程登录会话和其他网络服务提供安全性的协议。利用 SSH 协议可以有效防止远程管理过程中的信息泄露问题。
从客户端来看,SSH提供两种级别的安全验证:
第一种级别(基于口令的安全验证):只要你知道自己帐号和口令,就可以登录到远程主机。所有传输的数据都会被加密,但是不能保证你正在连接的服务器就是你想连接的服务器。可能会有别的服务器在冒充真正的服务器,也就是受到“中间人”这种方式的攻击。
第二种级别(基于密匙的安全验证)ssh-keygen:需要依靠密匙,你必须为自己创建一对密匙,并把公用密匙放在需要访问的服务器上。如果你要连接到SSH服务器上,客户端软件就会向服务器发出请求,请求用你的密匙进行安全验证。服务器收到请求之后,先在该服务器上你的主目录下寻找你的公用密匙,然后把它和你发送过来的公用密匙进行比较。如果两个密匙一致,服务器就用公用密匙加密“质询”(challenge)并把它发送给客户端软件。客户端软件收到“质询”之后就可以用你的私人密匙解密再把它发送给服务器。用这种方式,你必须知道自己密匙的口令。但是,与第一种级别相比,第二种级别不需要在网络上传送口令。第二种级别不仅加密所有传送的数据,而且“中间人”这种攻击方式也是不可能的(因为他没有你的私人密匙)。但是整个登录的过程可能需要10秒 。
ssh-keygen有很多的参数,比如这里的-t -b -C都是他的一些参数。
2、-t rsa:t是type的缩写
-t即指定密钥的类型,密钥的类型有两种,一种是RSA,一种是DSA:
RSA:RSA加密算法是一种非对称加密算法,是由三个麻省理工的牛人弄出来的,RSA是他们三个人姓的开头首字母组合。
DSA:Digital Signature Algorithm (DSA)是Schnorr和ElGamal签名算法的变种。
为了让两个linux机器之间使用ssh不需要用户名和密码。所以采用了数字签名RSA或者DSA来完成这个操作。ssh-keygen默认使用rsa密钥,所以不加-t rsa也行,如果你想生成dsa密钥,就需要加参数-t dsa。
3、-b 4096:b是bit的缩写
-b 指定密钥长度。对于RSA密钥,最小要求768位,默认是2048位。命令中的4096指的是RSA密钥长度为4096位。
DSA密钥必须恰好是1024位(FIPS 186-2 标准的要求)。
4、-C "邮箱":C是comment的缩写
-C表示要提供一个新注释,用于识别这个密钥,所以“”里面不一定非要填邮箱,可以是任何内容,邮箱仅仅是识别用的key
总结:当你创建ssh的时候:-t 表示密钥的类型 ,-b表示密钥的长度,-C 用于识别这个密钥的注释 ,这个注释你可以输入任何内容,很多网站和软件用这个注释作为密钥的名字
今天工作中遇见了一个问题:执行git pull 命令时,默认合并了远端的某个分支,经过查阅资料发现是git的配置问题。
如图所示:
git 查看远端主机详细配置信息
git remote show origin
通过查看配置信息发现:我的本地分支在执行git pull命令的时候默认拉取的远端的develop分支,导致pull命令合并了远端的develop分支
本地关联远程分支命令:
git branch --set-upstream
修改关联
git branch --set-upstream-to origin/分支名
再次执行 git remote show origin 发现pull配置信息已成功修改
第一、下载安装包 RAR for Mac OS X,下载地址。
第二、解压压缩包,cd Downloads/rar 。
第三、使用以下命令安装 rar 和 unrar:
1、sudo install -c -o $USER rar /usr/local/bin
2、sudo install -c -o $USER unrar /usr/local/bin
第四、命令:
解压:unrar x fileName.rar(files with full path) dirName
压缩:rar a fileName.rar(files with full path) dirName
作者:懶仁
链接:https://www.jianshu.com/p/e001591f5366
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
模块化是大型前端项目的必备要素。JavaScript 从诞生至今,出现过各种各样的模块化方案,让我们一起来盘点下吧。
默认情况下,在浏览器宿主环境里定义的变量都是全局变量,如果页面引用了多个这样的 JavaScript 文件,很容易造成命名冲突。
// 定义全局变量
let count = 0;
const increase = () => ++count;
const reset = () => {
count = 0;
console.log("Count is reset.");
};
// 使用全局变量
increase();
reset();
为了避免全局污染,可以用匿名函数包裹起来,这就是最简单的 IIFE 模块(立即执行的函数表达式):
// 定义 IIFE 模块
const iifeCounterModule = (() => {
let count = 0;
return {
increase: () => ++count,
reset: () => {
count = 0;
console.log("Count is reset.");
}
};
})();
// 使用 IIFE 模块
iifeCounterModule.increase();
iifeCounterModule.reset();
IIFE 只暴露了一个全局的模块名,内部都是局部变量,大大减少了全局命名冲突。
每个 IIFE 模块都是一个全局变量,这些模块通常有自己的依赖。可以在模块内部直接使用依赖的全局变量,也可以把依赖作为参数传给 IIFE:
// 定义带有依赖的 IIFE 模块
const iifeCounterModule = ((dependencyModule1, dependencyModule2) => {
let count = 0;
return {
increase: () => ++count,
reset: () => {
count = 0;
console.log("Count is reset.");
}
};
})(dependencyModule1, dependencyModule2);
一些流行的库在早期版本都采用这模式,比如大名鼎鼎的 jQuery(最新版本也开始用 UMD 模块了,后面会介绍)。
还有一种 IIFE,在 API 声明上遵循了一种格式,就是在模块内部提前定义了这些 API 对应的变量,方便 API 之间互相调用:
// Define revealing module.
const revealingCounterModule = (() => {
let count = 0;
const increase = () => ++count;
const reset = () => {
count = 0;
console.log("Count is reset.");
};
return {
increase,
reset
};
})();
// Use revealing module.
revealingCounterModule.increase();
revealingCounterModule.reset();
CommonJS 最初叫 ServerJS,是由 Node.js 实现的模块化方案。默认情况下,每个 .js
文件就是一个模块,模块内部提供了一个module
和exports
变量,用于暴露模块的 API。使用 require
加载和使用模块。下面这段代码定义了一个计数器模块:
// 定义 CommonJS 模块: commonJSCounterModule.js.
const dependencyModule1 = require("./dependencyModule1");
const dependencyModule2 = require("./dependencyModule2");
let count = 0;
const increase = () => ++count;
const reset = () => {
count = 0;
console.log("Count is reset.");
};
exports.increase = increase;
exports.reset = reset;
// 或者这样:
module.exports = {
increase,
reset
};
使用这个模块:
// 使用 CommonJS 模块
const { increase, reset } = require("./commonJSCounterModule");
increase();
reset();
// 或者这样:
const commonJSCounterModule = require("./commonJSCounterModule");
commonJSCounterModule.increase();
commonJSCounterModule.reset();
在运行时,Node.js 会将文件内的代码包裹在一个函数内,然后通过参数传递exports
、module
变量和require
函数。
// Define CommonJS module: wrapped commonJSCounterModule.js.
(function (exports, require, module, __filename, __dirname) {
const dependencyModule1 = require("./dependencyModule1");
const dependencyModule2 = require("./dependencyModule2");
let count = 0;
const increase = () => ++count;
const reset = () => {
count = 0;
console.log("Count is reset.");
};
module.exports = {
increase,
reset
};
return module.exports;
}).call(thisValue, exports, require, module, filename, dirname);
// Use CommonJS module.
(function (exports, require, module, __filename, __dirname) {
const commonJSCounterModule = require("./commonJSCounterModule");
commonJSCounterModule.increase();
commonJSCounterModule.reset();
}).call(thisValue, exports, require, module, filename, dirname);
AMD(异步模块定义)也是一种模块格式,由 RequireJS 这个库实现。它通过define
函数定义模块,并接受模块名和依赖的模块名作为参数。
// 定义 AMD 模块
define("amdCounterModule", ["dependencyModule1", "dependencyModule2"],
(dependencyModule1, dependencyModule2) => {
let count = 0;
const increase = () => ++count;
const reset = () => {
count = 0;
console.log("Count is reset.");
};
return {
increase,
reset
};
});
也用 require
加载和使用模块:
require(["amdCounterModule"], amdCounterModule => {
amdCounterModule.increase();
amdCounterModule.reset();
});
跟 CommonJS 不同,这里的 requrie
接受一个回调函数,参数就是加载好的模块对象。
AMD 的define
函数还可以动态加载模块,只要给它传一个回调函数,并带上 require
参数:
// Use dynamic AMD module.
define(require => {
const dynamicDependencyModule1 = require("dependencyModule1");
const dynamicDependencyModule2 = require("dependencyModule2");
let count = 0;
const increase = () => ++count;
const reset = () => {
count = 0;
console.log("Count is reset.");
};
return {
increase,
reset
};
});
AMD 模块还可以给define
传递module
和exports
,这样就可以在内部使用 CommonJS 代码:
// 定义带有 CommonJS 代码的 AMD 模块
define((require, exports, module) => {
// CommonJS 代码
const dependencyModule1 = require("dependencyModule1");
const dependencyModule2 = require("dependencyModule2");
let count = 0;
const increase = () => ++count;
const reset = () => {
count = 0;
console.log("Count is reset.");
};
exports.increase = increase;
exports.reset = reset;
});
// 使用带有 CommonJS 代码的 AMD 模块
define(require => {
// CommonJS 代码
const counterModule = require("amdCounterModule");
counterModule.increase();
counterModule.reset();
});
UMD(通用模块定义),是一种支持多种环境的模块化格式,可同时用于 AMD 和 浏览器(或者 Node.js)环境。
兼容 AMD 和浏览器全局引入:
((root, factory) => {
// 检测是否存在 AMD/RequireJS 的 define 函数
if (typeof define === "function" && define.amd) {
// 如果是,在 define 函数内调用 factory
define("umdCounterModule", ["deependencyModule1", "dependencyModule2"], factory);
} else {
// 否则为浏览器环境,直接调用 factory
// 导入的依赖是全局变量(window 对象的属性)
// 导出的模块也是全局变量(window 对象的属性)
root.umdCounterModule = factory(root.deependencyModule1, root.dependencyModule2);
}
})(typeof self !== "undefined" ? self : this, (deependencyModule1, dependencyModule2) => {
// 具体的模块代码
let count = 0;
const increase = () => ++count;
const reset = () => {
count = 0;
console.log("Count is reset.");
};
return {
increase,
reset
};
});
看起来很复杂,其实就是个 IIFE。代码注释写得很清楚了,可以看看。
下面来看兼容 AMD 和 CommonJS(Node.js)模块的 UMD:
(define => define((require, exports, module) => {
// 模块代码
const dependencyModule1 = require("dependencyModule1");
const dependencyModule2 = require("dependencyModule2");
let count = 0;
const increase = () => ++count;
const reset = () => {
count = 0;
console.log("Count is reset.");
};
module.export = {
increase,
reset
};
}))(// 判断 CommonJS 里的 module 变量和 exports 变量是否存在
// 同时判断 AMD/RequireJS 的define 函数是否存在
typeof module === "object" && module.exports && typeof define !== "function"
? // 如果是 CommonJS/Node.js,手动定义一个 define 函数
factory => module.exports = factory(require, exports, module)
: // 否则是 AMD/RequireJS,直接使用 define 函数
define);
同样是个 IIFE,通过判断环境,选择执行对应的代码。
前面说到的几种模块格式,都是用到了各种技巧实现的,看起来眼花缭乱。终于,在 2015 年,ECMAScript 第 6 版(ES 2015,或者 ES6 )横空出世!它引入了一种全新的模块格式,主要语法就是 import
和epxort
关键字。来看 ES6 怎么定义模块:
// 定义 ES 模块:esCounterModule.js 或 esCounterModule.mjs.
import dependencyModule1 from "./dependencyModule1.mjs";
import dependencyModule2 from "./dependencyModule2.mjs";
let count = 0;
// 具名导出:
export const increase = () => ++count;
export const reset = () => {
count = 0;
console.log("Count is reset.");
};
// 默认导出
export default {
increase,
reset
};
浏览器里使用该模块,在 script
标签上加上type="module"
,表明引入的是 ES 模块。在 Node.js 环境中使用时,把扩展名改成 .mjs
。
// Use ES module.
//浏览器: <script type="module" src="esCounterModule.js"></script> or inline.
// 服务器:esCounterModule.mjs
import { increase, reset } from "./esCounterModule.mjs";
increase();
reset();
// Or import from default export:
import esCounterModule from "./esCounterModule.mjs";
esCounterModule.increase();
esCounterModule.reset();
浏览器如果不支持,可以加个兜底属性:
<script nomodule>
alert("Not supported.");
</script>
2020 年最新的 ESCMA 标准11版中引入了内置的 import
函数,用于动态加载 ES 模块。import
函数返回一个 Promise
,在它的then
回调里使用加载后的模块:
// 用 Promise API 加载动态 ES 模块
import("./esCounterModule.js").then(({ increase, reset }) => {
increase();
reset();
});
import("./esCounterModule.js").then(dynamicESCounterModule => {
dynamicESCounterModule.increase();
dynamicESCounterModule.reset();
});
由于返回的是 Promise
,那肯定也支持await
用法:
// 通过 async/await 使用 ES 动态模块
(async () => {
// 具名导出的模块
const { increase, reset } = await import("./esCounterModule.js");
increase();
reset();
// 默认导出的模块
const dynamicESCounterModule = await import("./esCounterModule.js");
dynamicESCounterModule.increase();
dynamicESCounterModule.reset();
})();
各平台对import
、export
和动态import
的兼容情况如下:
SystemJS 是一个 ES 模块语法转换库,以便支持低版本的 ES。例如,下面的模块是用 ES6 语法定义的:
// 定义 ES 模块
import dependencyModule1 from "./dependencyModule1.js";
import dependencyModule2 from "./dependencyModule2.js";
dependencyModule1.api1();
dependencyModule2.api2();
let count = 0;
// Named export:
export const increase = function () { return ++count };
export const reset = function () {
count = 0;
console.log("Count is reset.");
};
// Or default export:
export default {
increase,
reset
}
如果当前的运行环境(比如旧浏览器)不支持 ES6 语法,上面的代码就无法运行。一种方案是把上面的模块定义转换成 SystemJS 库的一个 API, System.register
:
// Define SystemJS module.
System.register(["./dependencyModule1.js", "./dependencyModule2.js"],
function (exports_1, context_1) {
"use strict";
var dependencyModule1_js_1, dependencyModule2_js_1, count, increase, reset;
var __moduleName = context_1 && context_1.id;
return {
setters: [
function (dependencyModule1_js_1_1) {
dependencyModule1_js_1 = dependencyModule1_js_1_1;
},
function (dependencyModule2_js_1_1) {
dependencyModule2_js_1 = dependencyModule2_js_1_1;
}
],
execute: function () {
dependencyModule1_js_1.default.api1();
dependencyModule2_js_1.default.api2();
count = 0;
// Named export:
exports_1("increase", increase = function () { return ++count };
exports_1("reset", reset = function () {
count = 0;
console.log("Count is reset.");
};);
// Or default export:
exports_1("default", {
increase,
reset
});
}
};
});
这样,import/export
关键字就不见了。Webpack、TypeScript 等可以自动完成这样的转换(后面会讲)。
SystemJS 也支持动态加载模块:
// Use SystemJS module with promise APIs.
System.import("./esCounterModule.js").then(dynamicESCounterModule => {
dynamicESCounterModule.increase();
dynamicESCounterModule.reset();
});
Webpack 是个强大的模块打包工具,可以将 AMD、CommonJS 和 ES Module 格式的模块转换并打包到单个 JS 文件。
Babel 是也个转换器,可将 ES6+ 代码转换成低版本的 ES。前面例子中的计数器模块用 Babel 转换后的代码是这样的:
// Babel.
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = void 0;
function _interopRequireDefault(obj)
{ return obj && obj.__esModule ? obj : { "default": obj }; }
// Define ES module: esCounterModule.js.
var dependencyModule1 = _interopRequireDefault(require("./amdDependencyModule1"));
var dependencyModule2 = _interopRequireDefault(require("./commonJSDependencyModule2"));
dependencyModule1["default"].api1();
dependencyModule2["default"].api2();
var count = 0;
var increase = function () { return ++count; };
var reset = function () {
count = 0;
console.log("Count is reset.");
};
exports["default"] = {
increase: increase,
reset: reset
};
引入该模块的index.js
将会转换成:
// Babel.
function _interopRequireDefault(obj)
{ return obj && obj.__esModule ? obj : { "default": obj }; }
// Use ES module: index.js
var esCounterModule = _interopRequireDefault(require("./esCounterModule.js"));
esCounterModule["default"].increase();
esCounterModule["default"].reset();
以上是 Babel 的默认转换行为,它还可以结合其他插件使用,比如前面提到的 SystemJS。经过配置,Babel 可将 AMD、CJS、ES Module 转换成 System 模块格式。
TypeScript 是 JavaScript 的超集,可以支持所有 JavaScript 语法,包括 ES6 模块语法。它在转换时,可以保留 ES6 语法,也可以转换成 AMD、CJS、UMD、SystemJS 等格式,取决于配置:
{
"compilerOptions": {
"module": "ES2020", // None, CommonJS, AMD, System, UMD, ES6, ES2015, ES2020, ESNext.
}
}
TypeScript 还支持 module
和namespace
关键字,表示内部模块。
module Counter {
let count = 0;
export const increase = () => ++count;
export const reset = () => {
count = 0;
console.log("Count is reset.");
};
}
namespace Counter {
let count = 0;
export const increase = () => ++count;
export const reset = () => {
count = 0;
console.log("Count is reset.");
};
}
都可以转换成 JavaScript 对象:
var Counter;
(function (Counter) {
var count = 0;
Counter.increase = function () { return ++count; };
Counter.reset = function () {
count = 0;
console.log("Count is reset.");
};
})(Counter || (Counter = {}));
以上提到的各种模块格式是在 JavaScript 语言演进过程中出现的模块化方案,各有其适用环境。随着标准化推进,Node.js 和最新的现代浏览器都开始支持 ES 模块格式。如果要在旧环境中使用模块化,可以通过 Webpack、Babel、TypeScript、SystemJS 等工具进行转换。
https 方式每次都要输入密码,按照如下设置即可输入一次就不用再手输入密码的困扰而且又享受 https 带来的极速
设置记住密码(默认15分钟):
git config --global credential.helper cache
如果想自己设置时间,可以这样做:
git config credential.helper 'cache --timeout=3600'
这样就设置一个小时之后失效
长期存储密码:
git config --global credential.helper store
增加远程地址的时候带上密码也是可以的。(推荐)
http://yourname:[email protected]/name/project.git
//深文件无法删除
git config —system core.longpaths true
把旧项目提交到git上,但是会有一些历史记录,这些历史记录中可能会有项目密码等敏感信息。如何删除这些历史记录,形成一个全新的仓库,并且保持代码不变呢?
1.切换到新的分支
git checkout --orphan latest_branch
缓存所有文件(除了.gitignore中声名排除的)
git add -A
提交跟踪过的文件(Commit the changes)
git commit -am "commit message"
删除master分支(Delete the branch)
git branch -D master
5.重命名当前分支为master(Rename the current branch to master)
git branch -m master
6.提交到远程master分支 (Finally, force update your repository)
git push -f origin master
npm install json-server -g
json-server mock/data.json -p 3003
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.