ES6基础

ECMAScript 6学习网站:http://es6.ruanyifeng.com/

1.let和var的比较

共同点:定义变量
区别:
1.范围不同

  • var变量可以跨代码块
  • let只在代码块内部有效
{
    var a = "jarry";
    let b = 20;
}

console.log(a);
if(typeof(b) == "undefined"){
    alert("undefined");
}

案例

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

a[2]();

2.定义顺序

console.log(a); //let 引用错误
let a = "jarry";

var 不会报错的原因是因为加载这个文件后,已经知道有这个变量,只是在执行的时候,还没有声明,所以不会报错,只是为undefined

2.const常量

只能一次赋值

const PI = 3.14159;
PI = 3.14;
Paste_Image.png

1.对象常量
对象的属性可以修改,对象的引用不能修改

const obj = {name:"jack"};
obj.name = "jarry";

2.冻结对象
防止修改对象的属性

const obj = Object.freeze({name:"jason"});
obj.name = "jarry";
console.log(obj.name);

3.解构赋值

1.数组解构赋值
必须按照顺序

let [a,b] = ["jack",20];
console.log(a);
console.log(b);

old version

var obj = {name:"jack",age:20};
var a = obj.name;
var b = obj.age;

2.对象解构赋值
可以乱序

var {name,age} = {name:"jack",age:20};
console.log(name);
console.log(age);

3.用途

  • 1.交换变量的值
let x = 1;
let y = 2;
[x, y] = [y, x];
  • 2.从函数返回多个值
// 返回一个数组
function func1() {
    return [1, 2, 3];
}
let [a, b, c] = func1();
//old version
function func1() {
    return [1, 2, 3];
}
var arr = func1();
let a = arr[0];
let b = arr[1];
let c = arr[2];
  • 3.返回一个对象
function func2() {
    return {
        foo: 1,
        bar: 2
    };
}
let { foo, bar } = func2();

4.参数有序和无序

  • 参数是一组有次序的值
//数组解构赋值
function func3([x, y, z]) {}
func3([1, 2, 3]);
  • 参数是一组无次序的值
//对象解构赋值
function func4({x, y, z}) { }
func4({z: 3, y: 2, x: 1});

4.模板字符串(增强版的字符串)

原始的字符串拼接方式:

let name = "jack";
let age = 20;
let str = name + " is " + age + "years old.";

模板字符串:

  • 嵌入变量
let str2 = `${name} is ${age} years old.`;
//str2.log + tab键
console.log(str2);
  • 保持原来的字符串格式
let str3 = `I love
    you!`;
console.log(str3);

5.箭头函数

允许使用“箭头”(=>)定义函数

  • 普通
//原始方式
let func = function(n){
    console.log(n);
}
func(2);
//n =>代表function(n)
let func1 = n => console.log(n);
func1(3);
  • 带有返回值的例子:
//原始方式
let func1 = function(n){
    return n * 2;
}
//自动返回=>的值
let func2 = n => n * 2;
  • 多个参数
//原始方式
let func1= function(a,b){
    a+=5;
    return a+b;
}
//多个参数
let func2 = (a,b) => {
    a+=5;
    return a+b;
};
console.log(func3(3,4));
  • 箭头函数返回对象
var initObj = id => ({id:id,name:"default"});
console.log(initObj(2));
  • 对象解构赋值
//拼接得到完整的名称
let full = ({first, last}) => first + " " + last;
console.log(full({first: "Michael", last: "Jackson"}));

常见案例:

  • 数组的map遍历
//原始方式
var arr =[3,4,2,1].map(function (n) {
    return n*2;
})
console.log(arr);
//箭头方式
var arr2=[1,2,4].map(n=>n*2);
console.log(arr2);
  • sort排序(升序)
//原始方式
var arr = [1,4,5,2].sort(function(a,b){
    return a - b;
});
//箭头方式
var arr2 = [1,4,5,2].sort((a,b) => b - a);
console.log(arr2);
  • 不传参数
    可以传多个也可以不传
let func5 = () => 5;
let func6 = (m,n) => m * n;
function func4(a){
    //参数数组
    console.log(arguments[2]);
}
func4(6,9,10);

6.Symbol 第七种数据类型

表示独一无二的值,防止对象属性的覆盖

  • 类型
let s1 = Symbol();
console.log(s1);
console.log(typeof s1);

运行结果是:

Symbol()
symbol
  • 属性覆盖
let obj = {name : "jack"};
obj.name = function(){
    console.log("jack");
}
obj.name();
  • 使用Symbol给对象添加属性
let obj = {name:"jason"};
//另外一个模块
let name = Symbol();
let age = Symbol();
//name是一个Symbol值,作为属性名
obj[name] = function(){
    console.log("jack");
};
obj[age] = 10;
console.log(obj.name);
console.log(obj[age]);
obj[name]();

7.==(等于)与 ===(恒等于)的区别

==(等于)
1、如果两个值类型相同,进行 === 比较。
2、如果两个值类型不同,他们可能相等。根据下面规则进行类型转换再比较:

  • a、如果一个是null、一个是undefined,那么[相等]。
  • b、如果一个是字符串,一个是数值,把字符串转换成数值再进行比较。
  • c、如果任一值是 true,把它转换成 1 再比较;如果任一值是 false,把它转换成 0 再比较。
  • d、如果一个是对象,另一个是数值或字符串,把对象转换成基础类型的值再比较。对象转换成基础类型,利用它的toString或者valueOf方法。 js核心内置类,会尝试valueOf先于toString;例外的是Date,Date利用的是toString转换。
// console.log({} == "abc");
// console.log("1" == 1);
// console.log("abc" == 'abc');
// let a = null;
// console.log(a == undefined);
//
// console.log(true == "1");

===(恒等于)
1、如果类型不同,就[不相等]
2、如果两个都是数值,并且是同一个值,那么[相等];(!例外)的是,如果其中至少一个是NaN,那么[不相等]。(判断一个值是否是NaN,只能用isNaN()来判断)
3、如果两个都是字符串,每个位置的字符都一样,那么[相等];否则[不相等]。
4、如果两个值都是true,或者都是false,那么[相等]。
5、如果两个值都引用同一个对象或函数,那么[相等];否则[不相等]。
6、如果两个值都是null,或者都是undefined,那么[相等]。

8.class关键字

class 语法糖
在原有语法基础上修改语法,提高语法的可读写,原来的语法仍然可以使用

  • 老版本
function User(name,age){
    this.name = name;
    this.age = age;
}

User.prototype.sayHi = function(){
    console.log(this.name);
}
  • class 语法糖
class User{
    //构造函数
    constructor(name,age){
        this.name = name;
        this.age = age;
    }
    sayHi(){
        console.log(this.name);
    }
}

let u1 = new User("jack",20);
u1.sayHi();

console.log(typeof User);

事实上,类的所有方法都定义在原型的上的

console.log(u1.sayHi === User.prototype.sayHi);

返回结果是true

9.继承

var count = 0;
class Point{
    constructor(x,y){
        this.x = x;
        this.y = y;
    }
    toString(){
        return this.x + " " + this.y;
    }
    //静态方法
    static count(){
        return count++;
    }
}

//本质上还是通过原型来实现继承
class My3DPoint extends Point{
    constructor(x,y,z){
        super(x,y); //向父类构造函数传参
        this.z = z;
    }
    toString(){
        return "3D:"+this.z + " "+super.toString();
    }
}

let p1 = new My3DPoint(20,30,40);
// console.log(p1.toString());
//// console.log(p1 instanceof My3DPoint);
// console.log(p1 instanceof Point);
// console.log(p1.constructor === My3DPoint);

My3DPoint.count();
console.log(Point.count());
console.log(Point.count());*/

10.new.target

//根据new.target是否返回undefined,来判断构造函数是怎么调用的
function Person(name) {
    if (new.target !== undefined) {
        this.name = name;
    } else {
        throw new Error('必须使用new生成实例');
    }
}

// 另一种写法
function Person(name) {
    if (new.target === Person) {
        this.name = name;
    } else {
        throw new Error('必须使用new生成实例');
    }
}

var p1 = new Person('张三'); // 正确
var p2 = Person.call(person, '张三');  // 报错*/

11.几种继承

1.原型继承

//父类型
function SuperType(){
    this.flag = true;
}

SuperType.prototype.getXX = function(){
    return this.flag;
}

//子类型
function SubType(){
    this.subFlag = false;
}

SubType.prototype = new SuperType();

//拷贝过程(可以这么理解)
//new SuperType() -> SubType.prototype -> s1

//检查是否继承了父类型的属性
var s1 = new SubType();
console.log(s1.getXX());

原型继承的问题:共享属性

function SuperType(){
    this.x = 10;
    this.colors = ["red","green","blue"];
}

SuperType.prototype.getXX = function(){
    return "xx";
}

//子类型
function SubType(){
    this.subFlag = false;
}
//继承
//原型的问题:当原型包含引用类型的属性时,这些属性会被所有实例共享
SubType.prototype = new SuperType();

var s1 = new SubType();
s1.colors.push("white");
s1.x = 9;
console.log(s1.colors);

var s2 = new SubType();
console.log(s2.colors);
console.log(s2.x);

这个结果:s2也会有white

2.构造函数继承

function SuperType(){
    this.colors = ["red","green","blue"];
}

function SubType(){
    //继承属性
    SuperType.call(this);
    //相当于
    /!*function SuperType(){
        s1.colors = ["red","green","blue"];
    }*!/
}

var s1 = new SubType();
s1.colors.push("white");
console.log(s1.colors);

var s2 = new SubType();
console.log(s2.colors);*/

构造函数继承的问题:
方法都在构造函数中定义,函数复用是个问题,而且在父类原型中定义的函数,对于子类也是不可见的。

3.组合继承(综合有点,避免缺点)

//原型+构造函数
function SuperType(name){
    this.name = name;
    this.colors = ["red","green","blue"];
}

SuperType.prototype.sayHi = function(){
    console.log("sayHi");
}

function SubType(name,age){
    //继承属性
    SuperType.call(this,name);
    this.age = age;
}

//继承函数
SubType.prototype = new SuperType();
//构造函数不能错
SubType.prototype.constructor = SubType;

//子类自己的函数
SubType.prototype.sayAge = function(){
    console.log(this.age);
}

var s1 = new SubType("jack",20);
s1.sayHi();
s1.sayAge();
s1.colors.push("white");
console.log(s1.colors);

var s2 = new SubType("jason",20);
console.log(s2.colors);

//根据constructor判断,当前对象由哪一个构造函数实例化出来的
console.log(s2.constructor === SubType);

12.Generator函数

Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同
和普通函数的区别

  • 1.返回值function*
  • 2.yield
    传统函数,一旦调用,从头至尾执行,根本停不下来

从语法上,首先可以把它理解成,Generator 函数是一个状态机,封装了多个内部状态

function* func(){
    yield "step1";  //状态
    console.log("step1");

    yield "step2";
    console.log("step2");

    return "result";
}

调用Generator函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象,也就是遍历器对象(Iterator Object)

let state = func();

执行流程:
next方法:第一次调用,Generator函数开始执行,直到遇到第一个yield语句为止。

state.next();

next方法返回一个对象,它的value属性就是当前yield语句的值step1。

state.next();
state.next();
console.log(state.next());

上面代码返回对象的内容:{ value: 'step1', done: false }
其中:done属性的值false,表示遍历还没有结束。

** Symbol.iterator 迭代器**

let arr = ['a', 'b', 'c'];
//数组迭代器对象
let iter = arr[Symbol.iterator]();
//迭代器iter.next()函数,返回值:{ value: 'a', done: false }
console.log(iter.next());

//遍历数组的所有元素
while(true){
    var obj = iter.next();
    if(obj.done === true){
        break;
    }
    console.log(obj.value);
}

for of循环

for(let item of iter){
    console.log(item);
}

案例
显示进度条->请求数据->获取数据成功,隐藏进度条

  • 普通方式
//显示进度条
function showLoadingProgress(){
    //不断刷新进度条
    //DOM
    var progress = document.getElementsByTagName("progress")[0];
    //定时器,每隔500毫秒,进度累加
    var interval = setInterval(function(){
        progress.value += 10;
        if(progress.style.display === "none"){
            clearInterval(interval); //取消定时器
        }
    },500);
}

//请求数据
function loadUIDataAsynchronously(callback){
    //模拟网络延时
    setTimeout(function(){
        //拿到数据了
        let dataNode = document.getElementById("data");
        dataNode.innerText = "假装从服务器拿到了数据,显示在这里...";
        //隐藏进度条
        callback();
    },3000);
}

//隐藏进度条
function hideLoadingProgress(){
    var progress = document.getElementsByTagName("progress")[0];
    progress.style.display = "none";
}

function loadUI(){
    //1.显示进度条
    showLoadingProgress();
    //2.请求数据
    loadUIDataAsynchronously(hideLoadingProgress);

}
//当页面加载完成之后,执行loadUI
window.onload = loadUI;
  • 使用Generator函数
//显示进度条
 function showLoadingProgress(){
     //不断刷新进度条
     //DOM
     var progress = document.getElementsByTagName("progress")[0];
     //定时器,每隔500毫秒,进度累加
     var interval = setInterval(function(){
        progress.value += 10;
         if(progress.style.display === "none"){
            clearInterval(interval); //取消定时器
         }
     },500);
 }

//请求数据
function loadUIDataAsynchronously(){
    //模拟网络延时
    setTimeout(function(){
        //拿到数据了
        let dataNode = document.getElementById("data");
        dataNode.innerText = "假装从服务器拿到了数据,显示在这里...";
        //隐藏进度条
        loader.next();
    },3000);
}

//隐藏进度条
function hideLoadingProgress(){
    var progress = document.getElementsByTagName("progress")[0];
    progress.style.display = "none";
}

//异步操作的同步化表达
function* loadUI(){
    //1.显示进度条
    showLoadingProgress();
    //2.请求数据
    yield loadUIDataAsynchronously();
    //3.隐藏进度条
    hideLoadingProgress();
}
var loader;

window.onload = function(){
    loader = loadUI();
    loader.next();
}

next传参
yield句本身没有返回值,或者说总是返回undefined
next方法可以带一个参数,该参数就会被当作上一个yield语句的返回值。

Generator 函数从暂停状态到恢复运行,它的上下文状态(context)是不变的。通过next方法的参数, 就有办法在 Generator 函数开始运行之后,继续向函数体内部注入值。 也就是说,可以在 Generator 函数运行的不同阶段,从外部向内部注入不同的值,从而调整函数行为。

function* func2(){
    console.log("started");
    let r1 = yield ;
    console.log(r1); //输出yield返回值
    let r2 = yield ;
    console.log(r2);
}

let state = func2();
state.next();
state.next("a");
state.next();

//循环输出,通过传参,随时让循环重新开始
function* func3(){
    for(let i=0; i < 5; i++){
        let reset = yield i;
        console.log(reset);
        if(reset) i = -1;
    }
}

let state = func3();
console.log(state.next());
console.log(state.next());
//通过next传参,让yield有返回值
console.log(state.next(true));
console.log(state.next());
console.log(state.next());

案例2
按照流程执行:step1(value1) -> step2(value2) -> step3(value3) -> step4(value4)

  • 普通方式:
function step4(value3,callback){
    var value4 = `step4_${value3}`;
    callback(value4);
}

function step3(value2,callback){
    var value3 = `step3_${value2}`;
    callback(value3);
}

function step2(value1,callback){
    var value2 = `step2_${value1}`;
    callback(value2);
}

function step1(callback){
    var value1 = `step1_start `;
    callback(value1);
}

//给什么人看?
//回调嵌套
step1(function (value1) {
    step2(value1, function(value2) {
        step3(value2, function(value3) {
            step4(value3, function(value4) {
                console.log(value4);
            });
        });
    });
});*/

  • Generator 方式
function step4(value3){
    return `step4_${value3}`;
}

function step3(value2){
    return `step3_${value2}`;
}

function step2(value1){
    return `step2_${value1}`;
}

function step1(){
    return `step1_start `;
}

//控制流管理
function* stepFunc () {
    let value1; yield value1 = step1();
    let value2; yield value2 = step2(value1);
    let value3; yield value3 = step3(value2);
    let value4; yield value4 = step4(value3);
    console.log(value4);
}

//顺序执行
for(var i of stepFunc());

13.Promise

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大
例子
要求:
Ajax请求网络,json数据
请求成功:显示数据
请求失败:抛出异常
局部刷新

Promise对象的三种状态
Pending(进行中)、Resolved(已完成,又称 Fulfilled)和Rejected(已失败)

function ajax(url){
    var promise = new Promise(function(resolve,reject){
        var request = new XMLHttpRequest();
        request.open("GET",url)
        request.onreadystatechange = handler;
        request.responseType = "json"; //服务器响应数据的类型 json
        request.setRequestHeader("Accept","application/json");
        request.send();

        //回调
        function handler(){
            //4(完成)响应内容解析完成
            if(this.readyState !== 4){
                return;
            }
            if(this.status == 200){
                //请求成功:显示数据
                resolve(this.response);
            }
            else{
                reject(new Error(this.statusText));
            }
        }
    });

    return promise;
}

//指定resolve状态、reject状态的回调函数
ajax('test1.json').then(
    //resolve
    json => alert(json.message),
    //reject,可选的
    e => console.log(e.message)
);

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容