这是我参与「第四届青训营 」笔记创作活动的第1天
1、es6中let和var的区别
let声明的变量属于块级作用域,var声明的变量是函数作用域
1. 1、暂时新死区
指let声明的变量不会在作用域中被提升
//name被提升
console.log(age);//undefined
var name = 'hyy';
这一段代码中name被提升,相当于
var name;
console.log(name);
name = 'hyy';
而对于用let声明的age来说,age不被提升
//age不被提升
console.log(age);//ReferenceError:age 没有定义
let age = 18;
1. 2、全局声明
与 var 关键字不同,使用 let 在全局作用域中声明的变量不会成为 window 对象的属性(var声明的变量则会)。
var name = 'Matt';
console.log(window.name); // 'Matt'
let age = 26;
console.log(window.age); // undefined
1. 3、条件声明
在使用 var 声明变量时,由于声明会被提升,JavaScript 引擎会自动将多余的声明在作用域顶部合并为一个声明。因为 let 的作用域是块,所以不可能检查前面是否已经使用 let 声明过同名变量,同时也就不可能在没有声明的情况下声明它。
<script>
var name = 'Nicholas';
let age = 26;
</script>
<script>
// 假设脚本不确定页面中是否已经声明了同名变量
// 那它可以假设还没有声明过
var name = 'Matt';
// 这里没问题,因为可以被作为一个提升声明来处理
// 不需要检查之前是否声明过同名变量
let age = 36;
// 如果 age 之前声明过,这里会报错
</script>
1. 4、for循环中的let声明
用var声明内循环时,由于var会渗透到循环体外部,而对于let来说,let声明的变量只限于块级作用域内部, 不会被提升,所以不会又上面所诉的问题。
2、set和map的基本使用
2. 1、map的使用
map的定义
const m = new map()
使用对象初始化
const m = new map([
[key1: 'val1'],
[key2: 'val2'],
[key3: 'val3'],
])
遍历
1、for...of
for (let [key, value] of m) {
}
2、foreach
m.foreach(value => {
})
基本api
set(key, value):插入键值对,如果key已存在,则会覆盖原有的value
get(key):查找关键字,如果不存在,返回undefined
size:返回键值对数量
has(key):返回是否包含关键字key
delete(key):删除关键字key
clear():删除所有元素
2. 2、set的使用
基本api
add():添加元素
has():返回是否包含某个元素
size:返回元素数量
delete():删除某个元素
clear():删除所有元素
3、函数
3. 1、没有重载
es中定义的函数于Java中不一样,es中定义的函数没有重载,第二次定义的同名函数会把第一次定义的函数覆盖掉
let add = (a, b) => {
return a + b;
}
let add = (a, b) => {
return a - b
}
add(5, 5) // 0
参数初始化遵循“暂时性死区“
3. 2、闭包
首先闭包不是匿名函数
3. 2. 1 、匿名函数
匿名函数顾名思义就是没有名字的函数
匿名函数的定义并调用
(function(a){
console.log(a)
})(3) //3
3. 2. 2 、闭包
3. 2. 2. 1、作用域链的含义
以下代码涉及 3 个上下文:全局上下文、changeColor()的局部上下文和 swapColors()的局部上下文。全局上下文中有一个变量 color 和一个函数 changeColor()。changeColor()的局部上下文中有一个变量anotherColor 和一个函数 swapColors(),但在这里可以访问全局上下文中的变量 color。swapColors()的局部上下文中有一个变量 tempColor,只能在这个上下文中访问到。全局上下文和changeColor()的局部上下文都无法访问到 tempColor。而在 swapColors()中则可以访问另外两个上下文中的变量,因为它们都是父上下文。
作用域链为
window{
color
changeColor {
anotherColor
swapColors {
tempColor
}
}
}
这个作用域表示内部的上下文可以通过作用域链访问外部上下文的一切变量和函数
var color = "blue";
function changeColor() {
let anotherColor = "red";
function swapColors() {
let tempColor = anotherColor;
anotherColor = color;
color = tempColor;
// 这里可以访问 color、anotherColor 和 tempColor
}
// 这里可以访问 color 和 anotherColor,但访问不到 tempColor
swapColors();
}
// 这里只能访问 color
changeColor();
3. 2. 2. 2、
闭包的含义:闭包说白了就是函数的嵌套,内层的函数可以使用外层函数的所有变量,即使外层函数已经执行完毕(这点涉及JavaScript作用域链)。
function createComparisonFunction(propertyName) {
return function(object1, object2) {
"let value1 = object1[propertyName];
let value2 = object2[propertyName];"
if (value1 < value2) {
return -1;
} else if (value1 > value2) {
return 1;
} else {
return 0;
}
};
}
上面代码可以看到在""中的代码是在匿名函数中的一段,匿名函数调用了外层函数传入的变量propertyName
。
函数内部的代码在访问变量时,就会使用给定的名称从作用域链中查找变量。函数执行完毕后,局
部活动对象会被销毁,内存中就只剩下全局作用域。不过,闭包就不一样了。
闭包指在一个函数内部定义的函数会把其包含函数的活动对象添加到自己的作用域链中。
注意:因为闭包会保留它们包含函数的作用域,所以比其他函数更占用内存。过度使用闭包可能导致内存过度占用,因此建
议仅在十分必要时使用。V8 等优化的 JavaScript 引擎会努力回收被闭包困住的内存,不过我们还是建议在使用闭包时要
谨慎。
3. 2. 2. 3、闭包中的thit
由于每个函数在创建时都会自动创建两个特殊变量this和arguments,所以在内部函数很难访问到外部函数的this变量,但是可以将this保存到闭包可以访问的另一个变量中,而访问到外部函数的this
let object = {
identity: 'My Object',
getIdentityFunc() {
let that = this; //通过that接收,然后由于闭包中内部函数可以访问外部函数的变量
return function() {
return that.identity;
};
}
}
4、函数中的this和arguments
4. 1、this
在JavaScript中,this通常指的是执行时的调用者,而不是定义它的对象 例如:
const person = {
name: "hyy",
talk: function() {
console.log(this);
}
}
person.talk();
const talk = person.talk;
talk();
运行结果:
{name: 'hyy', talk: ƒ}
Window
bind()函数,可以绑定this的取值。例如:
const talk = person.talk.bind(person);
箭头函数不重新绑定this的取值 例如:
const person = {
talk: function() {
setTimeout(function() {
console.log(this);
}, 1000);
}
};
person.talk(); // 输出Window
const person = {
talk: function() {
setTimeout(() => {
console.log(this);
}, 1000);
}
};
person.talk(); // 输出 {talk: f}
4. 2、arguments
arguments是一个传递给函数的参数的类数组对象
这有MDN官网比较详细的介绍
developer.mozilla.org/zh-CN/docs/…