2018-07-24 汉得日记

ES6的继续学习

早上吴老师带我们快速过了一下es6的知识,包括import/export,let/const,箭头函数,模板字符串,Promise和对象解构赋值的相关知识。

由于之前的准备不是很充分,所以需要接下来的进一步巩固和复习:

参考资料:阮一峰的ES6教程

对象的拓展
有时变量多写起来真的很麻烦,很多繁琐的差不多的重复工作,es6为我们提供了多种更加便利的声明变量的形式——变量的解构赋值

es6允许按照一定的模式,从数组和对象中提取值,对变量进行赋值。本质是模式匹配。

变量的声明和赋值是一体的,使用let或者const不可以重复定义

在对象中的方法可以简写。

    const o = {
    hello() {
        return "Hello!";
    }
    };

    // 等同于

    const o = {
    hello: function() {
        return "Hello!";
    }
    };

自己写了个实际的例子,顺便使用了刚学的模板字符串:

let birth = '1996/03/25';

const Person = {

name: 'kiri',

//等同于birth: birth
birth,

// 等同于hello: function ()...
hello() { console.log(`我的名字是${this.name}

我的生日是${this.birth}`); }

};
Person.hello();

控制台中输出为:

我的名字是kiri

我的生日是2000/01/01

对象和数组的解构

1.es6里对象可采用以下简洁的写法进行解构赋值:
let {name,age,id}={name:'cursor',age:19,id:'vc6dfuoc91vpdfoi87s'};
console.log(name);  
console.log(age);   
console.log(id);    

当如果对象的属性值是一个变量时,调用必须使用变量名:

let {type:tipType,min:minNumber}={type:'message',min:20};
console.log(tipType);   
console.log(minNumber); 
console.log(type)   //type is not defined
2.数组的嵌套解构:

注意:前后结构需要一致,不然会报错

let [age, [{name: fname}]] = [20, [{
    name: 'qc'
}]];


console.log(age); //20
console.log(fname); //qc
3.数组的不完全解构:可以看出根据赋值结构进行匹配:
let [name,[age,[fname],[lname]],email]=['steven',[20,['qc'],[]]];
console.log(name);  //steven
console.log(age);   //20
console.log(fname); //qc
console.log(lname); //undefined
console.log(email); //undefined
4.解构对象的默认值.

在给对象或者与元素赋值时,可给被赋值的对象设置一个默认值,当被复制对象无法通过解构赋值取到值时会被赋予默认值。

默认值的生效条件是对象的属性值严格等于undefined。

5.字符串解构
const [a,b,c,d,e,f]="hello";
console.log(a); //h
console.log(b); //e
console.log(c); //l
console.log(d); //l
console.log(e); //o
console.log(f); //undefined

let和const的用法巩固

1.let是块级作用域,而var是函数作用域,

所以下面的代码如果使用var,最后输出的是10。

var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
    console.log(i);
};
}
a[6](); // 10

上面代码中,变量i是var命令声明的,在全局范围内都有效,所以全局只有一个变量i。每一次循环,变量i的值都会发生改变,而循环内被赋给数组a的函数内部的console.log(i),里面的i指向的就是全局的i。也就是说,所有数组a的成员里面的i,指向的都是同一个i,导致运行时输出的是最后一轮的i的值,也就是 10。

如果使用let,声明的变量仅在块级作用域内有效,最后输出的是 6。

var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
    console.log(i);
};
}
a[6](); // 6

上面代码中,变量i是let声明的,当前的i只在本轮循环有效,所以每一次循环的i其实都是一个新的变量,所以最后输出的是6。你可能会问,如果每一轮循环的变量i都是重新声明的,那它怎么知道上一轮循环的值,从而计算出本轮循环的值?这是因为 JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算。

2.不存在变量提升

简单来说。let只支持先声明再调用,不存在像var一样的变量提升(即可以先调用后声明)。

    // var 的情况
    console.log(foo); // 输出undefined
    var foo = 2;

    // let 的情况
    console.log(bar); // 报错ReferenceError
    let bar = 2;
3.不允许重复声明

let不允许在相同作用域内,重复声明同一个变量。

因此,不能在函数内部重新声明参数。

function func(arg) {
let arg; // 报错
}

function func(arg) {
{
    let arg; // 不报错
}
}
4.const的基本用法

const声明一个只读的常量。一旦声明,常量的值就不能改变

const PI = 3.1415;
PI // 3.1415

PI = 3;
// TypeError: Assignment to constant variable.

const声明的变量不得改变值,这意味着,const一旦声明变量,就必须立即初始化,不能留到以后赋值。

const foo;
// SyntaxError: Missing initializer in const declaration

const的作用域与let命令相同:只在声明所在的块级作用域内有效。

if (true) {
const MAX = 5;
}

MAX // Uncaught ReferenceError: MAX is not defined
5.const的本质

const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动

简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心。

const foo = {};

// 为 foo 添加一个属性,可以成功
foo.prop = 123;
foo.prop // 123

// 将 foo 指向另一个对象,就会报错
foo = {}; // TypeError: "foo" is read-only

Promise对象**

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大

Promise对象有以下两个特点。

(1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。

(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。

Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。

下面是一个Promise对象的简单例子。

function timeout(ms) {
return new Promise((resolve, reject) => {
    setTimeout(resolve, ms, 'done');
});
}

timeout(100).then((value) => {
console.log(value);
});

上面代码中,timeout方法返回一个Promise实例,表示一段时间以后才会发生的结果。过了指定的时间(ms参数)以后,Promise实例的状态变为resolved,就会触发then方法绑定的回调函数

编程风格

(1)let 取代 var

建议不再使用var命令,而是使用let命令取代

(2)全局常量和线程安全

在let和const之间,建议优先使用const,尤其是在全局环境,不应该设置变量,只应设置常量。

const优于let有几个原因。一个是const可以提醒阅读程序的人,这个变量不应该改变;另一个是const比较符合函数式编程思想,运算不改变值,只是新建值,而且这样也有利于将来的分布式运算;最后一个原因是 JavaScript 编译器会对const进行优化,所以多使用const,有利于提高程序的运行效率,也就是说let和const的本质区别,其实是编译器内部的处理不同。

(3)字符串

静态字符串一律使用单引号或反引号,不使用双引号。动态字符串使用反引号。

// good
const a = 'foobar';
const b = `foo${a}bar`;
const c = 'foobar';

(4) 解构赋值

使用数组成员对变量赋值时,优先使用解构赋值。

const arr = [1, 2, 3, 4];
// good
const [first, second] = arr;
console.log(first);
console.log(second);

(5)对象的成员

函数的参数如果是对象的成员,优先使用解构赋值。

function getFullName({firstName, lastName }) {
return `我的名字是${firstName} ${lastName}`
}
const obj=getFullName({"firstName":"卢","lastName":"基狗"});
console.log(obj)

上述代码就输出结果:我的名字是卢基狗

(6)数组的拷贝

使用扩展运算符(…)拷贝数组。

const arr=[1,2,3,4,5];
app=[...arr];
console.log(app);

(7)多使用箭头函数

const func3=(a,b) => {
    return 'a'
}
const func3=() => 'a'

箭头函数取代Function.prototype.bind,不应再用 self/_this/that 绑定 this。

// bad
const self = this;
const boundMethod = function(...params) {
return method.apply(self, params);
}

// acceptable
const boundMethod = method.bind(this);

// best
const boundMethod = (...params) => method.apply(this, params);

简单的、单行的、不会复用的函数,建议采用箭头函数。如果函数体较为复杂,行数较多,还是应该采用传统的函数写法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值