最后
推荐一些系统学习的途径和方法。
每个Web开发人员必备,很权威很齐全的Web开发文档。作为学习辞典使用,可以查询到每个概念、方法、属性的详细解释,注意使用英文关键字搜索。里面的一些 HTML,CSS,HTTP 技术教程也相当不错。
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
HTML 和 CSS:
小黄书是公司带我的姐姐推荐给给我看的,她跟我说JS好才是王道,有空把三本都看了,于是我在摸鱼的时候看完了小黄书上册…
小黄书涉及到的知识点还是非常的精细的,这里记录的是对于我来说让我眼前一亮的知识点,换句话就是我之前都不是很理解或者说是没有涉猎到的知识点。也不是代表除了这些别的我都懂了。总之读书是真的很重要。以后会一直记录下去。
函数作用域
function test(a) {
b = a * 5; // 报错 b没有被定义
let b;
console.log(b);
}
function test(a) {
b = a * 5;
var b; // 正常运行 var会变量提升
console.log(b);
}
console.log(b) // 报错 找不到b
function test(a) {
b = a * 5;
// 正常运行 函数作用域找不到b 就会去外层找
console.log(b);
}
var b;
总结:
-
如果函数内部找不到 就会往外层找 直到到最外层的Global中
-
在函数中 就算使用 var 定义的变量 也不会被提升到全局的 Global中,但是还是会变量提升
-
最好的建议还是使用 let 和 const 因为这里的两个是不会变量提升的,不容易出错
闭包不污染全局变量
function test1() {
var a = 1
}
test1() // 正常运行
(function test2() {})();
test2(); // 报错 找不到 test2这个函数
总结:
-
正常使用函数确实是可以让函数里面的成员变量私有化,但是函数自己本身是被定义和赋值到全局对象中了,这个或多或少也是一种污染
-
使用闭包可以解决这个问题,函数变量名被隐藏在自身中意味着不会非必要地污染外部作用域
-
当函数可以记住并访问所在的词法作用域,即使函数是在当前词法作用域之外执行,这时就产生了闭包。
块作用域
if(true){
var a = 5;
}
console.log(a); // 5
if (true) {
let b = 5;
}
console.log(b); // ReferenceError: b is not defined
总结:
-
在过去 JS 是没有块级作用域这个概念的,只有函数作用域,因为使用var定义的变量都会被提升到最上面(如果var定义在函数里面也会被提升到函数的最上面)
-
但是好在ES6推出了let和const关键字,让JS也拥有了块级作用域
变量提升的细节
a = 2;
var a;
console.log( a );
// 编译后的代码
var a;
a = 2;
console.log( a ); // 答案是2
console.log( a );
var a = 2;//浏览器解析到这里 编译器会将这段代码编译成 var a; a = 2; var a会被提到最前面
// 最终经过编译的最终代码是
var a
console.log( a ); // undefined 因为 a只是定义还没有赋值 所以是 undefined
a = 2
foo(); // 不是 ReferenceError, 而是 TypeError!
var foo = function bar() { // … }; // 这里不是函数声明 而是函数表达式
// 编译器处理后
var foo
foo() // TypeError 类型错误 还没声明 foo是函数就使用函数的调用方法
foo = function bar(){}
foo(); // 1
var foo;
function foo() { console.log( 1 ); } // 函数会被提升到最前面,换句话说,函数最先提升
foo = function() { console.log( 2 ); };
总结:
-
只有声明本身会被提升,赋值和其他的逻辑会留在原地
-
var 和 函数声明都会提升
-
函数声明会被提升,但是函数表达式却不会被提升
-
函数会首先被提升,然后才是变量
闭包
function setupBot(name, selector) {
$( selector ).click( function activator() {
console.log( "Activating: " + name );
} );
}
setupBot( “Closure Bot 1”, “#bot_1” );
setupBot( “Closure Bot 2”, “#bot_2” );
// 以上的函数就是一个闭包
function foo() {
var a = 2;
function bar() {
console.log( a );
}
return bar;
}
var baz = foo(); baz(); // 2 —— 朋友,这就是闭包的效果。
总结:
-
函数是在它本身的词法作用域以外执行。
-
只要使用了回调函数,实际上就是在使用闭包!
循环和闭包
for (var i=1; i<=5; i++) {
setTimeout( function timer() {
console.log( i );
}, i*1000 );
}
// 结果: 输出5次6
// 因为setTimeout()是一个异步的函数,for循环结束了才会执行setTimeout,而for循环结束的时候 i是等于6的 所以最终会输出5次6
// 因为我们试图在每次循环的时候都能保存下一个i的副本,但是实际上因为作用域,每次都是同一个i,最终i被赋值成了6,所以输出了5次6
解决方案:
for (var i=1; i<=5; i++) {
(function(j) {
setTimeout( function timer() {
console.log( j );
}, j*1000 );
})( i );
}
// 这样就可以解决了, 每次运行的时候都将i存进一个立即执行函数里面,立即执行函数又作用域又可以防治变量污染,就可以解决这个问题了
最优方案:
for (let i=1; i<=5; i++) {
紧跟潮流
大前端和全栈是以后前端的一个趋势,懂后端的前端,懂各端的前端更加具有竞争力,以后可以往这个方向靠拢。
这边整理了一个对标“阿里 50W”年薪企业高级前端工程师成长路线,由于图片太大仅展示一小部分