es6简单介绍
let和const
原先声明变量的形式
var test = 5; //全局变量
function a()
{
var cc=3; //局部变量
alert(test);
}
function b(){alert(test);}
test = 5;//全局变量
function a()
{
aa=3; //全局变量
alert(test);
}
在es6之前,作用域只有全局作用域和函数作用域,没有块级作用域,所以考虑如下代码
{ var a = 6;
var a = 8}
console.log(a) // 答案是8
我们本来想着用{}表示一块作用域,外面应该访问不到里面的变量,但是事实是var声明的变量泄漏到全局作用域了。所以引出let
let有三个个特点:
- 不能重复赋值
- 作用域是局部作用域
- 不存在变量提升
{let a=10;
let a=11}
Uncaught SyntaxError: Identifier 'a' has already been declared
{let a = 10}
a
Uncaught ReferenceError: a is not defined
at <anonymous>:1:1
作用域是块级作用域
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[0](); // 10
因为var定义的是全局,所以在内存中只维护一块空间,每次+1的时候这块空间的值发生改变,而数组中的每个函数的引用都指向这一块空间,当最后调用的时候那块空间的值就是10了,所以结果就是10了
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[0](); // 0
let声明的是块级作用域,所以每一次循环的i其实都是一个新的变量,每次循环都会创建新的内存空间,每个放到数组中的函数都指向对应的内存空间的值,等调用的时候就调用指向的值。那么问题来了,如果每一轮循环的变量i都是重新声明的,那它怎么知道上一轮循环的值,从而计算出本轮循环的值?这是因为 JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算
变量提升
console.log(foo); // undefined
var foo = 2;
在es6之前,变量使用在定义之前得到的结果是undefiend,这种现象叫做变量提升,这其实不符合正常的编程逻辑。
js引擎在解释的时候从上到下,先找定义的变量,也就是说下面代码其实是这样的
var foo;
console.log(foo); // undefined
foo = 2;
有了let之后
console.log(foo); // 报错
let foo = 2;
块级作用域
内层变量可能会覆盖外层变量
var tmp = 5;
function f() {
console.log(tmp);
if (false) {
var tmp = 'hello world';
}
}
f(); // undefined
至于结果为啥是undefined参考变量提升的解释。在内部定义的var tmp = 'hello world';
的在解释的时候在函数作用域内是先var tmp
的
用来计数的循环变量泄露为全局变量
for (var i = 0; i < 5; i++) {
console.log(s[i]);
}
console.log(i); // 5
变量i只用来控制循环,但是循环结束后,它并没有消失,泄露成了全局变量。
const
const定义的变量有两点需要注意:
- 不能只用来声明,声明的时候就必须赋值
- 不能修改
const的作用域与let命令相同:只在声明所在的块级作用域内有效。
模板字符串
在es6之前,我们拼接字符串都有+
,这种方式是繁琐的,可以使用反引号(`)标识。
反引号主要有3个作用:
- 当作普通字符串
- 定义多行字符串(相当于python的三引号)
- 在字符串中嵌入变量
d
10
`iloce${d}`
"iloce10"
箭头函数
箭头函数就是函数的一种缩写形式
//无形参
var f = () => 5;
// 等同于
var f = function () { return 5 };
//多个形参
var sum = (num1, num2) => num1 + num2;
// 等同于
var sum = function(num1, num2) {
return num1 + num2;
};
箭头函数有一点需要注意
在es6之前,函数体内的this对象,就是使用时所在的对象,而不是定义时所在的对象
var person = {
name:'jack',
age:18,
fav:function(){
console.log(this)
}
}
person.fav();
用了箭头函数之后,函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象
var person2 = {
name:'jack',
age:18,
fav: ()=>{
// 当前this指向了定义时person2对象时所处的对象(window)
console.log(this);
}
}
person2.fav();
为了解决这个问题, 使用对象的单体模式:
var person2 = {
name:'jack',
age:18,
fav() {
// 当前this指向了定义时person2对象时所处的对象(window)
console.log(this);
}
}
person2.fav();
面向对象
在es6之前创建对象是这样做的
function Animal(name,age){
this.name = name;
this.age = age;
}
Animal.prototype.showName = function(){
console.log(this.name);
console.log(this.age);
}
var a = new Animal('小黄',5);
a.showName();
我们在python中通过class就能定义一个对象,在es6中也可以这样做
class People {
// 类似python中的init
constructor(name,age){
this.age = age;
this.name = name;
}
eat(){console.log('111')}
study() {console.log('1222')}
}
定义“类”的方法的时候,前面不需要加上function这个关键字,直接把函数定义放进去了就可以了。另外,方法之间不需要逗号分隔,加了会报错。