iwalking11 / front-end-knowledge Goto Github PK
View Code? Open in Web Editor NEW前端知识总结
前端知识总结
git的基础功能中有个打标签的功能。这功能其实非常有用,往往在线上发布时会用到。
像其他版本控制系统(VCS)一样,Git 可以给历史中的某一个提交打上标签,以示重要。 比较有代表性的是人们会使用这个功能来标记发布结点(v1.0 等等)。
当你在线上发布最新的代码时,最好每次都打上一个tag,因为当这次发布的代码失败,有bug的时候,你可以快速checkout上次的稳定tag,
以实现代码的快速回滚,待你修复好新代码后,再重新发布,打上一个稳定的标记tag。
另外在一些场景也会用到打tag来实现持久化构建的功能。
$ git tag
v0.1
v1.3
**列出特定的标签:**
$ git tag -l 'v1.8.5*'
v1.8.5
v1.8.5-rc0
v1.8.5-rc1
v1.8.5-rc2
v1.8.5-rc3
v1.8.5.1
v1.8.5.2
v1.8.5.3
v1.8.5.4
v1.8.5.5
$ git tag v1.4-lw
$ git tag
v0.1
v1.3
v1.4
v1.4-lw
v1.5
$ git show v1.4-lw
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <[email protected]>
Date: Mon Mar 17 21:52:11 2008 -0700
changed the version number
$ git tag -a v1.4 -m 'my version 1.4'
$ git tag
v0.1
v1.3
v1.4
$ git show v1.4
tag v1.4
Tagger: Ben Straub <[email protected]>
Date: Sat May 3 20:19:12 2014 -0700
my version 1.4
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <[email protected]>
Date: Mon Mar 17 21:52:11 2008 -0700
changed the version number
在commit列表中也可以选择任意一个commit new tag
默认情况下,git push 命令并不会传送标签到远程仓库服务器上。 在创建完标签后你必须显式地推送标签到共享服务器上。 这个过程就像共享远程分支一样 - 你可以运行 git push origin [tagname]。
//提交单个tag
$ git push origin v1.5
//提交全部tag
$ git push origin --tags
webstorm push时,左下角Push Tags同样要打勾
在 Git 中你并不能真的检出一个标签,因为它们并不能像分支一样来回移动。 如果你想要工作目录与仓库中特定的标签版本完全一样,可以使用 git checkout -b [branchname] [tagname] 在特定的标签上创建一个新分支:
$ git checkout -b version2 v2.0.0
Switched to a new branch 'version2'
在线上执行回滚的时候,用一个可用稳定的tag,创建一个新的临时分支,让该分支在线上先跑。然后再去修复master的代码,等待修复完,再重新把线上分支切回master,以实现快速代码回滚。
缺点:
每次都要手动去删除服务器端的文件,再上传,比较繁琐,而且容易误操作
const upload = (localPath, remotePath) => {
return new Promise((resolve, reject) => {
const sftp = new Client();
sftp.on('keyboard-interactive', (name, instructions, instructionsLang, prompts, finish) => {
finish([config.password]);
});
sftp.connect(options).then(() => {
return sftp.put(localPath, remotePath);
}).then(() => {
console.log('\033[42;30m DONE \033[40;32m' + localPath + '\033[0m');
sftp.end();
resolve(localPath);
}).catch((err) => {
console.log(err, 'catch error');
reject(err);
});
});
};
打包后自动执行上传的脚本文件即可
配置好后,通过可视化的deploy按钮操作就能上传
也可以设置监听文件改变自动更新服务器文件
只看过相关介绍,暂时还没有尝试过。主要是通过触发git等版本控制工具webhook,推送信息到jenkins
参考:
利用nodejs监控文件变化并使用sftp上传到服务器
真▪一行代码完成从前端代码build到部署线上
前端自动化部署系统
/* 默认值。内容不会被修剪,会呈现在元素框之外 */
overflow: visible;
/* 内容会被修剪,并且其余内容不可见 */
overflow: hidden;
/* 内容会被修剪,浏览器会显示滚动条以便查看其余内容 */
overflow: scroll;
/* 由浏览器定夺,如果内容被修剪,就会显示滚动条 */
overflow: auto;
/* 规定从父元素继承overflow属性的值 */
overflow: inherit;
参考资料:
MDN-overflow
console.log('1');
setTimeout(function() {
console.log('2');
process.nextTick(function() {
console.log('3');
})
new Promise(function(resolve) {
console.log('4');
resolve();
}).then(function() {
console.log('5')
})
})
process.nextTick(function() {
console.log('6');
})
new Promise(function(resolve) {
console.log('7');
resolve();
}).then(function() {
console.log('8')
})
setTimeout(function() {
console.log('9');
process.nextTick(function() {
console.log('10');
})
new Promise(function(resolve) {
console.log('11');
resolve();
}).then(function() {
console.log('12')
})
})
1:this永远指向一个对象;
2:this的指向完全取决于函数调用的位置;
因为函数在js中既可以当做值传递和返回,也可当做对象和构造函数,所有函数在运行时需要确定其当前的运行环境,this就出生了,所以,this会根据运行环境的改变而改变,同时,函数中的this也只能在运行时才能最终确定运行环境;
function fun(){
console.log(this.s);
}
var obj = {
s:'1',
f:fun
}
var s = '2';
obj.f(); //1
fun(); //2
function foo() {
console.log(this.a);
}
var obj2 = {
a: 2,
fn: foo
};
var obj1 = {
a: 1,
o1: obj2
};
obj1.o1.fn(); // 2
箭头函数的this指向定义时所在的对象,其实质是因为箭头函数没有自己的this,用的是外层的this
在setTimeOut()或setInterval()这样的方法中,如果传入的函数包含this, 那么,默认情况下,函数中的this会指向window对象。这是由于setTimeout()调用的代码运行在与所在函数完全分离的执行环境上。这会导致这些代码中包含的 this 关键字会指向 window (或全局)对象。
如何获取需要的this对象
function doClick(){
var that = this;
setInterval(function() {
console.log(that.msg);
}, 1000);
}
function doClick(){
setInterval(function() {
console.log(this.msg);
}.bind(this), 1000); //利用bind()将this绑定到这个函数上
}
function doClick(){
setInterval(() => {
console.log(this.msg);
}, 100);
},
定义:direction 属性设置文本,表格列和水平排列的方向。
基本上,大家只要关心下面这两个属性值就好了:
direction: ltr; // 从左往右,默认值
direction: rtl; //从右往左
和float属性有些类似,writing-mode原本设计的是控制内联元素的显示的(即所谓的文本布局-Text Layout)。因为在亚洲,尤其像**这样的东亚国家,存在文字的排版不是水平式的,而是垂直的,例如**的古诗古文。因此,writing-mode就是用来实现文字可以竖着呈现的。
学习相比其他CSS属性要复杂一些,因为我们需要记住两套不同的语法。一个是IE私有属性,第二个是CSS3规范属性。
writing-mode: horizontal-tb; /* 默认值 */
writing-mode: vertical-rl;
writing-mode: vertical-lr;
-ms-writing-mode: lr-tb | rl-tb | tb-rl | bt-rl | tb-lr | bt-lr | lr-bt | rl-bt | lr | rl | tb
writing-mode: lr-tb | tb-rl | tb-lr (IE8+);
writing-mode: horizontal-tb | vertical-rl | vertical-lr;
实际开发用的上的其实也就这三种,可以和CSS3规范中的属性完全对应上。
writing-mode: vertical-lr;
writing-mode, direction, unicode-bidi(MDN文档)是CSS世界中3大可以改变文本布局流向的属性。其中direction, unicode-bidi属于近亲,经常在一起使用,也是唯二不受CSS3 all属性影响的CSS属性,基本上就是和内联元素一起使用使用,且据说貌似为阿拉伯文字设计。
乍一看,writing-mode似乎包含了direction, unicode-bidi某些功能和行为,例如vertical-rl的rl和direction的rtl值有相似之处,都是从右往左。然而,实际上,两者是没有交集的。因为vertical-rl此时的文档流为垂直方向,rl表示水平方向,此时再设置direction:rtl,实际上值rtl改变的是垂直方向的内联元素的文本方向,一横一纵,没有交集。而且writing-mode可以对块状元素产生影响,直接改变了CSS世界的纵横规则,要比direction强大和鬼畜的多。且据说貌似为东亚文字设计。
然而,CSS的奇妙就在于,某些特性当初可能就是问了某些图文排版设计,但是,我们可以利用其带来的特性,发挥自己的创造力,实现其他很多意想不到的效果。所以,上面出现的三剑客都是非常好的资源。
参考:
direction(MDN)
writing-mode(MDN)
CSS direction属性简介与实际应用
改变CSS世界纵横规则的writing-mode属性
git stash
保存当前的工作进度。会分别对暂存区和工作区的状态进行保存
git stash save "message..."
这条命令实际上是第一条 git stash
命令的完整版
git stash list
显示进度列表。此命令显然暗示了git stash 可以多次保存工作进度,并用在恢复时候进行选择
git stash pop [--index] [<stash>]
如果不使用任何参数,会恢复最新保存的工作进度,并将恢复的工作进度从存储的工作进度列表中清除。
如果提供参数(来自 git stash list
显示的列表),则从该 <stash>
中恢复。恢复完毕也将从进度列表中删除 <stash>
。
选项--index 除了恢复工作区的文件外,还尝试恢复暂存区。
git stash apply [--index] [<stash>]
除了不删除恢复的进度之外,其余和 git stash pop
命令一样
git stash clear
删除所有存储的进度
在Webstorm中使用stash
VCS / Git / Stash Changes
VCS / Git / UnStash Changes
使用一个规范的 Git 提交记录是很有必要的,这不仅让多人开发中的参与者能更好地了解项目的迭代历史和进程,也能在出现问题时快速定位,找到问题代码的提交记录。同时我们还可以使用工具根据提交记录自动生成更新说明 (CHANGELOG),方便用户了解每次更新的具体内容,也免去了项目维护者手动更新的痛苦。
目前前端社区中使用较多的 Git Commit 提交规范是 Angular 规范 (Git Commit Message Conventions ),Commit 的格式包含 Header、Body、Footer 三个部分:
<type>(<scope>): <subject>
<body>
<footer>
用于说明 commit 的类别,只允许使用下面7个标识。
feat:新功能(feature)
fix:修补bug
docs:文档(documentation)
style: 格式(不影响代码运行的变动)
refactor:重构(即不是新增功能,也不是修改bug的代码变动)
test:增加测试
chore:构建过程或辅助工具的变动
用于说明 commit 影响的范围,比如数据层、控制层、视图层等等,视项目不同而不同。
是 commit 目的的简短描述,不超过50个字符。
1.以动词开头,使用第一人称现在时,比如change,而不是changed或changes
2.第一个字母小写
3.结尾不加句号(.
详细描述(可不写)
修改不兼容变动以及关闭 Issue时(可不写)
1.提供更多的信息,方便排查与回退;
2.过滤关键字,迅速定位;
3.方便生成文档;
如果我们的提交都按照规范的话,那就很简单了。生成的文档包括以下三个部分:
New features
Bug fixes
Breaking changes.
每个部分都会罗列相关的 commit ,并且有指向这些 commit 的链接。当然,生成的文档允许手动修改,所以发布前,你还可以添加其他内容。
这里需要使用工具 Conventional Changelog 生成 Change log :
npm install -g conventional-changelog
cd jartto-domo
conventional-changelog -p angular -i CHANGELOG.md -w
为了方便使用,可以将其写入 package.json 的 scripts 字段。
{
"scripts": {
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -w -r 0"
}
}
这样,使用起来就很简单了:
npm run changelog
position 的常见四个属性值: relative,absolute,fixed,static。一般都要配合"left"、"top"、"right" 以及 "bottom" 属性使用。
**设置CSS盒模型为标准模型或IE模型。标准模型的宽度只包括content,二IE模型包括border和padding
box-sizing属性可以为三个值之一:
content-box,默认值,只计算内容的宽度,border和padding不计算入width之内
padding-box,padding计算入宽度内 (注:只有Firefox实现了这个值,但它在Firefox 50中被删除)
border-box,border和padding计算入宽度之内
如果一个容器中只有一行文字,对它实现居中相对比较简单,我们只需要设置它的实际高度height和所在行的高度line-height相等即可
只需要在父盒子设置:display: flex; justify-content:(平行方向) center;align-items: center(垂直方向); 就可以达到垂直水平居中
缺点:有兼容性问题
父盒子设置:display:table-cell; text-align:center;vertical-align:middle;
(父盒子外面需要再套一个div{display:table})
<div class="parent">
<div class="child">Demo</div>
</div>
<style>
.parent {
position: relative;
}
.child {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
</style>
.parent{
position:relative;
}
.child{
width: 100px;
height: 100px;
position: absolute;
top: 50%;
left: 50%;
margin: -50px 0 0 -50px;
}
缺点:需要确定子元素宽高
子元素可以是块级元素也可以是行内元素,没有影响
.parent{
position:relative
}
.child{
margin:auto;
height: 100px;
width: 100px;
position: absolute;
top: 0; left: 0; bottom: 0; right: 0;
}
需设置子元素宽高,否则子元素将与父元素宽高一致
解释:
通过以上描述,绝对居中(AbsoluteCentering)的工作机理可以阐述如下:
1、在普通内容流(normal content flow)中,margin:auto的效果等同于margin-top:0;margin-bottom:0。
2、position:absolute使绝对定位块跳出了内容流,内容流中的其余部分渲染时绝对定位部分不进行渲染。
3、为块区域设置top: 0; left: 0; bottom: 0; right: 0;将给浏览器重新分配一个边界框,此时该块block将填充其父元素的所有可用空间,父元素一般为body或者声明为position:relative;(非static)的容器。
4、 给内容块设置一个高度height或宽度width,能够防止内容块占据所有的可用空间,促使浏览器根据新的边界框重新计算margin:auto
5、由于内容块被绝对定位,脱离了正常的内容流,浏览器会给margin-top,margin-bottom相同的值,使元素块在先前定义的边界内居中。
这么看来, margin:auto似乎生来就是为绝对居中(Absolute Centering)设计的,所以绝对居中(Absolute Centering)应该都兼容符合标准的现代浏览器。
参考:
关于css水平垂直居中的总结
CSS中设置DIV垂直居中的N种方法 兼容IE浏览器
盘点8种CSS实现垂直居中水平居中的绝对定位居中技术
直接上代码:
计数器counter
<div class="main">
<div class="first">
<div class="second">伪元素content中counter计数器的使用</div>
<div class="second">伪元素content中counter计数器的使用</div>
</div>
<div class="first">
<div class="second">伪元素content中counter计数器的使用</div>
<div class="second">伪元素content中counter计数器的使用</div>
<div class="second">伪元素content中counter计数器的使用</div>
</div>
<div class="first">
<div class="second">伪元素content中counter计数器的使用</div>
<div class="second">伪元素content中counter计数器的使用</div>
</div>
</div>
.main {
width: 350px;
margin: 30px auto;
height: auto;
overflow: hidden;
box-shadow: 0px 1px 5px rgba(0, 0, 0, 0.5);
counter-reset: main;
color: #646452;
text-align: left;
.first {
counter-reset: submain;
&::before {
font-size: 18px;
font-weight: bold;
counter-increment: main;
display: inline-block;
padding: 5px;
content: "类别 " counter(main) ". ";
}
.second {
&::before {
padding: 5px 16px;
font-family: arial black;
display: inline-block;
counter-increment: submain;
content: counter(main) "." counter(submain) " ";
}
}
}
}
效果图:
嵌套计数器counters
<ul class="father">
<li class="son">我的爱好
<ul class="father">
<li class="son">爬山</li>
<li class="son">追剧</li>
<li class="son">旅游</li>
</ul>
</li>
<li class="son">我的偶像
<ul class="father">
<li class="son">王昱珩
<ul class="father">
<li class="son">最强大脑第二季选手</li>
<li class="son">最强大脑第五季水之队队长</li>
</ul>
</li>
<li class="son">胡歌</li>
<li class="son">陈默</li>
</ul>
</li>
<li class="son">web前端</li>
<li class="son">啦啦啦啦啦</li>
</ul>
li {
list-style: none;
}
.father {
text-align: left;
padding-left: 20px;
counter-reset: count;
line-height: 1.6;
color: #666;
}
.son:before {
content: counters(count, '-') '. ';
counter-increment: count;
font-family: arial black;
}
效果图:
浏览器性能优化的文章中经常会出现事件委托(代理),那事件代理是利用了事件的什么机制?事件冒泡机制。事件冒泡又是什么呢,这篇我们就来总结一下DOM事件流
DOM事件:用户或浏览器执行的动作,如click
事件处理程序:是响应某个事件的函数,如 onclick()也叫事件侦听器
DOM有4次版本更新,与DOM版本变更,产生了3种不同的DOM事件定义 DOM0级、DOM2级、DOM3级。由于DOM1级中没有事件的相关内容,所以没有DOM1级事件。
DOM0事件
<p onclick="alert('click')">HTML事件处理程序</p>
问题
使用js的写法
var btn = document.getElementById('btn');
btn.onclick = function(){
alert(this.innerHTML);
}
问题
当希望为同一个元素/标签绑定多个同类型事件的时候(如,为上面的这个p标签绑定3个点击事件),是不被允许的
DOM2级事件
el.addEventListener(event-name, callback, useCapture)
event-name
: 事件名称,可以是标准的DOM事件
callbakc
: 回调函数,当事件触发时,函数会被注入一个参数为当前的事件对象 event
useCapture
: 是否以捕获的方式触发,默认为true
DOM3级事件
在DOM2级事件的基础上添加了更多的事件类
假如在一个button上注册了一个click事件,又在其它父元素div上注册了一个click事件,那么当我们点击button,是先触发父元素上的事件,还是button上的事件呢,这就需要一种约定去规范事件的执行顺序,就是事件执行的流程。
W3C标准中规定了事件流的三个阶段的顺序:
我们要想实现点击某个元素,只触发这个元素本身的事件,而不影响父元素或子元素呢?
所以这里需要一种方法,不让事件向下捕获或向上冒泡
所以有了 e.stopPropagation() 方法,用于阻止事件的继续传递。
执行这条语句,无论我们是使用捕获模式还是冒泡模式,事件都不会继续传递,只会响应我们点击的元素。
利用事件冒泡或捕获的机制,我们可以对事件绑定做一些优化。
在JS中,如果我们注册的事件越来越多,页面的性能就越来越差,因为:
document.getElementById('wrap').addEventListener('click', function(e){
if(e.target.classList.contains('box')){
logerBox.innerHTML += '<p>'+type+': '+e.target.id+'</p>';
}
}, useCapture)
对于堆叠上下文,在MDN中的描述是:
层叠上下文是HTML元素的三维概念,这些HTML元素在一条假想的相对于面向(电脑屏幕的)视窗或者网页的用户的z轴上延伸,HTML元素依据其自身属性按照优先级顺序占用层叠上下文的空间。 ž 轴即用户与屏幕间看不见的垂直线。
层叠水平顺序决定了同一个层叠上下文中元素在ž轴上的显示顺序
以下摘自 MDN:
Note: 层叠上下文的层级是 HTML 元素层级的一个层级,因为只有某些元素才会创建层叠上下文。可以这样说,没有创建自己的层叠上下文的元素 将被父层叠上下文包含。
参考资料:
MDN-The stacking context
css层叠上下文【stacking context】和层叠顺序【stacking order】
先看看关于换行的CSS属性吧!
white-space
normal: 忽略/合并空白
pre: 保留空白,如同<pre>的行为
nowrap: 忽略/合并空白,文本不会换行,直到遇到<br/>
pre-wrap: 保留空白,但是会正常地进行换行
pre-line: 忽略/合并空白,但是会正常地进行换行
inherit: 从父元素继承。
word-wrap
normal: 只在允许的断字点换行
break-word: 在长单词或URL地址内部进行换行
word-break
normal:依照亚洲和非亚洲语言的文本规则,允许在单词内换行。
keep-all:让亚洲语言文本如同非亚洲语言文本那样不允许在任意单词内换行。
break-all:允许非亚洲语言文本行如同亚洲语言文本那样可以在任意单词内换行。
一个个试一下
MDN的这张表格总结了各种 white-space 值的行为:
一般情况下,想要换行=使用word-wrap:break-word;
就OK了。
另外我们还可以通过word-break:keep-all;white-space:nowrap;
或word-break:keep-all;white-space:pre;
来实现打死都不换行的效果
相关代码:
demo
参考:
CSS魔法堂:重新认识Box Model、IFC、BFC和Collapsing margins
彻底搞懂word-break、word-wrap、white-space
(MDN) white-space
标准盒子模型:宽度=内容的宽度(content)+ border + padding + margin
低版本IE盒子模型:宽度=内容宽度(content+border+padding)+ margin
页面渲染时,dom 元素所采用的 布局模型。可通过box-sizing进行设置。根据计算宽高的区域可分为:
CSS选择符:id选择器(#myid)、类选择器(.myclassname)、标签选择器(div, h1, p)、相邻选择器(h1 + p)、子选择器(ul > li)、后代选择器(li a)、通配符选择器(*)、属性选择器(a[rel="external"])、伪类选择器(a:hover, li:nth-child)
可继承的属性:font-size, font-family, color
不可继承的样式:border, padding, margin, width, height
优先级(就近原则):!important > style 属性 > id > class > tag
!important 比内联优先级高
元素选择符: 1
class选择符: 10
id选择符:100
元素标签:1000(内联样式)
!important声明的样式优先级最高,如果冲突再进行计算。
如果优先级相同,则选择最后出现的样式。
继承得到的样式的优先级最低
p:first-of-type 选择属于其父元素的首个元素
p:last-of-type 选择属于其父元素的最后元素
p:only-of-type 选择属于其父元素唯一的元素
p:only-child 选择属于其父元素的唯一子元素
p:nth-child(2) 选择属于其父元素的第二个子元素
:enabled :disabled 表单控件的禁用状态。
:checked 单选框或复选框被选中。
拓展问题:
::after 和 :after 一个冒号和两个冒号有什么区别
::after表示法是在CSS 3中引入的,::符号是用来区分伪类和伪元素的。支持CSS3的浏览器同时也都支持CSS2中引入的表示法:after。
注: IE8仅支持:after。
1.DNS域名解析;
2.建立TCP连接;
3.发送HTTP请求;
4.服务器处理请求;
5.返回响应结果;
6.关闭TCP连接;
7.浏览器解析HTML;
8.浏览器布局渲染;
MDN的解释:load 应该仅用于检测一个完全加载的页面 当一个资源及其依赖资源已完成加载时,将触发load事件。
意思是页面的html、css、js、图片等资源都已经加载完之后才会触发 load 事件
MDN的解释:当初始的 HTML 文档被完全加载和解析完成之后,DOMContentLoaded 事件被触发,而无需等待样式表、图像和子框架的完成加载。
意思是HTML下载、解析完毕之后就触发。
参考:
细说浏览器输入URL后发生了什么
浏览器中输入url后发生了什么
浏览器加载网页时的过程是什么?
再谈 load 与 DOMContentLoaded
1、对象的方法
2、原型方法
3、事件的回调
4、构造函数
回顾 MDN 给出的解释:箭头函数表达式的语法比函数表达式更短,并且没有自己的this,arguments,super或 new.target。这些函数表达式更适用于那些本来需要匿名函数的地方,并且它们不能用作构造函数。
所以说,箭头函数无疑是 ES6 带来的重大改进,在正确的场合使用箭头函数,能让代码变得更加简洁短小。但箭头函数也不是万能的,不能用的时候,千万别硬往上套。比如,在需要动态上下文的场景中,使用箭头函数需要格外地小心,这些场景包括:对象的方法、原型方法、事件的回调、构造函数。 并非一定要用箭头函数,才能解决问题。
有两段关于for循环的代码,区别是一段使用var变量,一段使用let变量
for (var i = 0; i <5; i++) { setTimeout(()=>console.log("i:",i), 1000); } //输出结果:5 5 5 5 5
for (let i = 0; i < 5; i++) { setTimeout(()=>console.log("i:",i), 1000); } //输出结果:0 1 2 3 4 5
为什么输出结果不一样,原因后面再说,先看关于let的一些描述:
function a() {
for (var i = 0; i <5; i++) {
setTimeout(()=>console.log("i:",i), 1000);
}
console.log(i); //5 表明var变量的作用域在整个a函数中
};
a(); //通过setTimeout中的匿名函数引用函数外部变量 i 实际上就是一个闭包的效果
function a() {
for (let i = 0; i <5; i++) {
setTimeout(()=>console.log("i:",i), 1000);
}
console.log(i); //Uncaught ReferenceError: a is not defined 表明let变量的作用域只在for循环代码块中
};
a();
let a =3;
let a =5;
// Uncaught SyntaxError: Identifier 'a' has already been declared
let x = 'global'
{
console.log(x) // Uncaught ReferenceError: x is not defined
let x = 1
}
如果变量没有提升,应该就会打印全部的x:'global',所有存在变量提升
既然let有变量提升,为什么在 let x 之前使用 x 会报错,原因有两个
看到这里,你应该明白了 let 到底有没有提升:
创建一个js变量有三个过程:「创建create、初始化initialize 和赋值assign」
但是看了这么多,好像还是不太能解释一开始的两段代码为什么不一致啊?
在ES标准中,有一段是关于CreatePerIterationEnvironment,也就是for语句每次循环所要建立环境的步骤,里面有提及有关词法环境的相关步骤(LexicalEnvironment),这与使用let时会有关。所以,如果你使用了let而不是var,let的变量除了作用域是在for区块中,而且会为每次循环执行建立新的词法环境(LexicalEnvironment),拷贝所有的变量名称与值到下个循环执行。以最简单的方式改写原先的问题中的代码,相当于下面这样写:
for (let i = 0; i <5; i++) {
let j = i;
setTimeout(()=>console.log("i:", j), 1000);
}
这其实也是MDN中介绍let时使用的例子,就是为了方便我们理解let的块级作用域
简单的理解上面所说的就是:
for( let i = 0; i< 5; i++) 这句话的圆括号之间,有一个隐藏的作用域
for( let i = 0; i< 5; i++) { 循环体 } 在每次执行循环体之前,JS 引擎会把 i 在循环体的上下文中重新声明及初始化一次。
那样的话,5 次循环,就会有 5 个不同的 i,console.log 出来的 i 当然也是不同的值。
再加上隐藏作用域里的 i,一共有 6 个 i。
参考:
1.怎么理解for循环中用let声明的迭代变量每次是新的变量?
2.我用了两个月的时间才理解 let
3.What's the difference between using “let” and “var” to declare a variable in JavaScript?
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.