参考书籍:http://es6.ruanyifeng.com/
参考视频:https://www.bilibili.com/video/av47304735
全部篇章:
ES6知识点归纳(一)——var、let、const、箭头函数、函数参数的默认值、ES6模版字符串
ES6知识点归纳(二)——对象解构、数组解构、for of循环、新增的方法、剩余参数、扩展运算符
ES6知识点归纳(三)——Promise、Symbol、模块(Modules)、class继承、Iterator、Generator、Proxy、Set、WeakSet、Map、WeakMap
文章目录
var、let、const
var
- 可以重复声明、可以重新赋值
- 在函数中声明变量,则只能在函数中使用(var 声明的变量的作用域属于 Function Scope)
- 用 var 在 if 语句的代码块中声明,因为没有函数,所以在 if 语句的代码块外也能访问
function hi() {
if (true) {
var i = "hi";
console.log(i); //hi
}
console.log(i); //hi
}
hi();
console.log(i); //delete.html:26 Uncaught ReferenceError: i is not defined
- 存在变量提升,声明的语句会被提升到作用域最上方,赋值语句不被提升,留在原地
console.log(i);
var i = 1; //undefined
//相当于
//var i;
//console.log(i);
//i=1;
注意:
for (var i = 0; i < 5; i++) {
console.log(i); //0 1 2 3 4,这行语句在for循环执行的时候立即执行
setTimeout(function() {
console.log(i); //5 5 5 5 5 ,for循环结束后执行
}, 0);
}
- 解决方法就是改用 let
let
- 不可以重复声明、可以重新赋值
- 用 let 声明变量,只在代码块内可访问(let 声明的变量的作用域属于 block scope)
let count = 10; let discount = 0.9; const key = "abc"; if (count > 5) { let discount = 0.5; console.log(discount); //0.5 } console.log(discount); //0.9
let count = 10; let count = 1; // Uncaught SyntaxError: Identifier 'count' has already been declared
- 存在变量提升,但因为存在作用域死区(Temporal dead zone),但是若想在当前块级作用域中,这个变量声明之前引用这个变量,就会报错。
- 即在这个作用域开始直到这个变量声明之前,这个变量都处在临时性死区当中,这时引用它会报 ReferenceError
const
- 不可以重复声明、不可以重新赋值
- 用 const 声明时必须立刻赋值
- 用 const 声明变量,只在代码块内可访问(属于 block scope)
const key = "123"; key = "456"; //delete.html:19 Uncaught TypeError: Assignment to constant variable.
const key;//Uncaught SyntaxError: Missing initializer in const declaration
if (true) { const key = "123"; console.log(key); //123 } console.log(key); //delete.html:22 Uncaught ReferenceError: key is not defined
注意:这样也是不可以的
let i = 0;
const i = 1; //Uncaught SyntaxError: Identifier 'i' has already been declared
- 若用 const 声明时,给它的是一个对象,那么,对象的属性仍能改变,因为 const 指向的是对象的引用,这个引用不能变
const person = {
name: "Alred",
age: 30
};
person = {
name: "Alfred"
};
//delete.html:22 Uncaught TypeError: Assignment to constant variable.
const person = {
name: "Alred",
age: 30
};
person.age = 20;
console.log(person); //正常输出且不报错,其中age为20
- 也可以这样赋值
let abc = {
name: "Raymond"
};
const person2 = abc;
- 若希望对象的属性值也不修改的话,可以使用 Object.freeze()方法
const person = {
name: "Alred",
age: 30
};
Object.freeze(person); //不允许改变对象的属性值
person.age = 20;
console.log(person.age); //30
- 存在变量提升,也存在作用域死区(和 let 一样)
三者如何选择
- 默认使用 const
- 当变量需要重新绑定或更新的时候使用 let
- 在 ES6 中尽量不适用 var
箭头函数
语法简明
() => { ... } // 没有参数
x => { ... } // 一个参数,括号可加可不加(x)=>{...}
(x, y) => { ... } // 多个参数
简单例子
const numbers = [1, 2, 3, 4, 5];
const double = numbers.map(function(number) {
return number * 2;
});
const double2 = numbers.map(number => {
return number * 2;
});
console.log(double); // [2, 4, 6, 8, 10]
console.log(double2); // [2, 4, 6, 8, 10]
可以隐式返回
x => {
return x * x;
}; // 语句块
x => x * x; // 表达式,和上一行作用相同
const numbers = [1, 2, 3, 4, 5];
const double = numbers.map(number => {
return number * 2;
});
const double2 = numbers.map(number => number * 2);
console.log(double); // [2, 4, 6, 8, 10]
console.log(double2); // [2, 4, 6, 8, 10]
this
- 箭头函数没有自己的 this 值,它的 this 是继承它的父作用域的(即上层作用域)
- 箭头函数在指定的时候 this 已经确定,一般情况下不会因为调用而改变,不过会随上层作用域的 this 的变化而变化
- 先看一个例子
const Alfred = {
name: "Alfred",
hobbies: ["singing", "dancing", "composeing"],
printHobbies: function() {
console.log(this);
this.hobbies.map(function(hobby) {
console.log(this); //window
console.log(`${this.name} loves ${hobby}`); //输出内容都缺了Alfred
});
}
};
Alfred.printHobbies();
调用 Alfred 中的 printHobbies(),第一个 this 指向 Alfred,然后 printHobbies 里的那个函数,是 map 方法的一个回调函数,这个方法是独立运行的,因此这个方法指向的是 window
- 解决方法
const Alfred = {
name: "Alfred",
hobbies: ["singing", "dancing", "composeing"],
printHobbies: function() {
var _this = this;
this.hobbies.map(function(hobby) {
console.log(this);
console.log(`${_this.name} loves ${hobby}`);
});
}
};
Alfred.printHobbies();
或者,使用箭头函数
const Alfred = {
name: "Alfred",
hobbies: ["singing", "dancing", "composeing"],
printHobbies: function() {
this.hobbies.map(hobby => {
console.log(this);
console.log(`${this.name} loves ${hobby}`);
});
}
};
Alfred.printHobbies();
- 另外:由于箭头函数是匿名函数,所以一般会把函数赋值给一个变量
const greet = name => {
console.log(name);
};
greet("Alfred");
箭头函数的不适用场景
- 不能作为构造函数,不能用于定义对象方法
// const person = (name, points) => { //Uncaught TypeError: person is not a constructor
const person = function(name, points) {
this.name = name;
this.points = points;
};
const Alfred = new person("Alfred", 30);
// person.prototype.updatePoints = () => {
// console.log(this);//Window,因为箭头函数不会绑定this,但是方法又需要绑定到对象上,因此不能用
// this.points--;
// console.log(this.points);
// }
// Alfred.updatePoints(); //NaN
person.prototype.updatePoints = function() {
console.log(this); //person
this.points--;
console.log(this.points);
};
Alfred.updatePoints(); //29
- 真的需要用到 this 的时候不能使用箭头函数
<div
id="app"
style="width: 50px ; height: 50px; background-color: #000000;"
></div>
const app = document.getElementById("app");
// app.addEventListener('click', () => {
app.addEventListener("click", function() {
//此处的方法需要绑定到app上,但是用箭头函数是不会进行绑定的
console.log(this); //Window
this.style.height = "100px";
setTimeout(() => {
//此处希望this仍然指向app,使用箭头函数可以使this与外层保持一致
this.style.height = "50px";
}, 500);
});
- 需要使用 arguments 对象时不能使用箭头函数
// sum函数返回所有参数的和
// const sum = () => {
// return Array.from(arguments).reduce((preSum, value) => preSum + value, 0)
// }
// sum(1, 2, 3); //delete.html:19 Uncaught ReferenceError: arguments is not defined
const sum = function() {
return Array.from(arguments).reduce((preSum, value) => preSum + value, 0);
};
console.log(sum(1, 2, 3)); //6
函数参数的默认值
function multiply(a, b) {
a = a || 5;
b = b || 3;
console.log(a * b);
}
multiply(); //15,均使用了默认值
multiply(2, 3); //6,使用了参数的值
multiply(1); //3,b使用了默认值
multiply(undefined, 2); //10,a使用了默认值
用 ES6 可以简化为
function multiply(a = 5, b = 3) {
console.log(a * b);
}
multiply(); //15,均使用了默认值
multiply(2, 3); //6,使用了参数的值
multiply(1); //3,b使用了默认值
multiply(undefined, 2); //10,a使用了默认值,不能是multiply(, 2);必须要指明前面的参数
multiply(null, 2); //0,不会使用默认值
- 如果有传参,则使用传进来的值,如果没有传值,函数默认传的是 undefined,if(typeof a === undefined),就会使用默认值
ES6 模版字符串
基础用法
- 用反引号"`"来定义字符串
- 用
${}
来引用变量,也可以放表达式、对象的属性、函数 - 直接使用反引号可以保存 html 代码的层级结构,不需要用\或数组去模拟
- 模版字符串可以嵌套使用
const person = "Alfred";
const age = 30;
const sentence = person + " is " + age + " years old"; //es5
const sentence2 = `${person} is ${age * 2} years old`; //es6
const template = `
<div>
<p>Hello</p>
</div>
`.trim();
console.log(sentence);
console.log(sentence2);
console.log(template);
简单应用:
const Alfred = {
name: "Alfred",
todos: [
{
thing: "Go to the gym",
completed: false
},
{
thing: "sing a song",
completed: true
},
{
thing: "dance",
completed: false
}
]
};
const template = `
<ul>
${Alfred.todos
.map(
todos => `
<li>
${todos.thing} ${todos.completed ? "(yes)" : "(no)"}
</li>`
)
.join("")}
</ul>
`;
console.log(template);
document.body.innerHTML = template;
根据以上例子,还可以将读取对象内容的代码封装成函数
function renderTodos(todos) {
return `<ul>
${todos
.map(
todo => `
<li>
${todo.thing} ${todo.completed ? "(yes)" : "(no)"}
</li>`
)
.join("")}
</ul>`;
}
const template = `${renderTodos(Alfred.todos)}`;
document.body.innerHTML = template;
标签模版
- 即在模版字符串中添加标签,根据我们自定义的规则,返回我们想要的字符串
- 标签对应 js 里的一个函数名
- 使用标签模版字符串时,最后那个字符串返回的内容是由标签(函数)决定的
- 这个函数可以接受模版字符串作为参数,第一个参数为模版字符串里的普通字符,其后的参数是模版字符串里的变量
//参数可以用逗号分隔一个一个写
//也可以用ES6中的剩余参数,values是一个数组,是又剩余的参数组成
function hightlight(strings, ...values) {
// debugger;//可以看到strings,values里有什么
const hightlighted = values.map(
value => `<span class='hightlight'>${value}</span>`
); //遍历变量的数组,给变量加一个span标签和hightlight样式
// console.log(hightlighted);
//将普通字符和处理后的变量拼接在一起
let str = "";
// strings.forEach((string, i) => {str += `${string}${hightlighted[i]}`;});
//由于strings里最后一个是空字符串,因此要改写,以免拼接后句子中出现underfined
strings.forEach((string, i) => {
str += `${string}${hightlighted[i] || ""}`;
});
return str;
}
const user = "Alfred";
const topic = "Learn ES6";
const sentence = hightlight`${user} has commented on your topic ${topic}`;
// console.log(sentence);
document.body.innerHTML = sentence;
以上代码优化、简化:
function hightlight(strings, ...values) {
const hightlighted = values.map(
value => `<span class='hightlight'>${value}</span>`
);
//字符串拼接也可以改为,reduce
return strings.reduce(
(prev, curr, i) => `${prev}${curr}${hightlighted[i] || ""}`,
""
);
}
const user = "Alfred";
const topic = "Learn ES6";
const sentence = hightlight`${user} has commented on your topic ${topic}`;
document.body.innerHTML = sentence;
注意:
- 如果模版字符串是以变量开头或结尾的话,打印参数 strings,会看到里面有空字符串
forEach():https://www.runoob.com/jsref/jsref-foreach.html
reduce():https://www.runoob.com/jsref/jsref-reduce.html
最佳实践——过滤用户输入(防 xss 攻击)
更多关于标签模版的内容:https://www.cnblogs.com/sminocence/p/6832331.html