let、const关键字
共同点
let和const关键词与var都是用来声明变量的,在使用方式上没有什么不同:
var varname = 'crane';
let username = 'paper_crane';
const age = 22;
如上例子,varname、username和age都是有效的变量,并且可以通过变量名来访问他们的值。
不同点
第一个不同点是let和const声明的变量都是被定义在块级作用域中,var声明的变量都是在函数作用域里面:
function test() {
if (true) {
var varname = 'crane';
let username = 'paper_crane';
const age = 22;
}
console.log(varname); // crane
console.log(username); // error
console.log(age); // error
}
test();
第二个不同点是let和const声明的变量没有被提升:
function test() {
console.log(varname); // undefined
console.log(username); // error
console.log(age); // error
var varname = 'crane';
let username = 'paper_crane';
const age = 22;
}
在上面的例子中,varname显示的是undefined,是因为没有初始化,但是已经在执行环境中声明了,而username和age则直接报错。
let username = 'crane';
function test() {
console.log(username); // Uncaught ReferenceError: username is not defined
let username = 'paper_crane';
}
test();
let username = 'crane';
function test() {
console.log(username); // crane
// let username = 'paper_crane';
}
test();
在上面的例子中,test函数内不使用let声明username,则会访问到全局的username,但是声明了就会报出引用错误的error。
第三个不同点是let和const声明的变量没有存入执行环境的变量对象:
var varname = 'crane';
let username = 'paper_crane';
const age = 22;
console.log(window.varname); // crane
console.log(window.username); // undefined
console.log(window.age); // undefined
以上例子在全局环境下定义了三个变量varname、username、age,然而通过访问window的属性只能访问到varname,所以username和age并没有保存到变量对象中。
第四个不同点是const声明的变量是一个常量,一经定义,无法修改,否则会报错:
const age = 22;
age = 23; // Uncaught TypeError: Assignment to constant variable.
使用:
由于let声明的变量是属于块级作用域的,所以配合for循环使用可以减少使用闭包:
for (let i = 0; i < 10; i++) {
setTimeout(function() {
console.log(i);
}, 1000);
}
// output: 0 1 2 3 4 5 6 7 8 9
模板字符串
模板字符串可以有效的减少字符串拼接的繁琐过程,其使用反引号``(注意不是单引号,此按键在ESC键下方)括住字符串,通过${}来使用变量或者表达式:
let username = 'crane',
age = 22;
let str = 'I am ' + username + ', ' + age + ' years old!' + ' I have ' + (1 + 1) + ' gfs.',
templateStr = `I am ${ username }, ${ age } years old! I have ${ 1 + 1} gfs.`;
console.log(str); // I am crane, 22 years old! I have 2 gfs.
console.log(templateStr); // I am crane, 22 years old! I have 2 gfs.
箭头函数
箭头函数就像是一个匿名函数,不使用function关键字,使用方式如下:
let arrowFunc = () => {}; // 没有参数,没有返回值
let arrowFunc = oneArg => expression; // 一个参数,隐式返回一个表达式
let arrowFunc = (arg1, arg2, arg3) => { // 多个参数需要括号
return arg; // 花括号括住函数主体,返回值需用return关键字
};
值得注意的一点是,箭头函数里面的this值是遵循词法作用域规则的,详情请看 JavaScript执行环境、作用域及this值
var username = 'paper_crane';
let obj = {
username: 'crane',
normalFunc: function() {
console.log(this.username);
},
arrowFunc: () => {
console.log(this.username)
}
}
obj.normalFunc(); // crane
obj.arrowFunc(); // paer_paper
obj.normalFunc.apply({username: 'apply'}); // apply
obj.arrowFunc.apply({username: 'apply'}); // paper_crane
解构赋值
解构赋值是将一个对象的键值赋值给变量的一个快速方法:
let obj = {
username: 'crane',
age: 22,
carrer: 'software engineer'
}
let { username } = obj,
{ age, carrer } = obj;
console.log(username, age, carrer);
...语法
let arr = ['crane', 22, 'software engineer'],
obj = {
username: 'crane',
age: 22,
carrer: 'software engineer'
},
copy = {...obj};
function test(username, ...rest) {
console.log(rest);
}
test('crane', 22, 'software engineer'); // 22, software engineer
test(...arr); // 22, software engineer
console.log(obj); // username: 'crane', age: 22, carrer: 'software engineer'
class
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
static sayInfo(name, age, school) {
console.log(name, age, school);
}
get name() {
return this._name;
}
set name(name) {
this._name = name;
}
sayName() {
console.log(this.name);
}
}
class Student extends Person {
constructor(name = 'crane', age = 22, school = 'SYSU') {
super(name, age);
this.school = school;
}
getSchool() {
return this.school;
}
}
var crane = new Student();
crane.sayName(); // crane
console.log(crane.getSchool()); // SYSU
Person.sayInfo(crane.name, crane.age, crane.school); // crane 22 SYSU
crane.sayInfo(crane.name, crane.age, crane.school); // Uncaught TypeError: crane.sayInfo is not a function
constructor是构造函数,如果继承了父类,需要在constructor里面调用super(),即调用父类的构造函数。第7行给Person类定义了一个静态方法。第11行和第15行给name属性定义了一个getter和setter。Student的构造函数使用了默认参数,当没有相关的参数传入的时候就会使用默认参数。class类没有私有属性和方法。