ES6新特性学习

ES6新特性学习

学习链接:http://es6.ruanyifeng.com/

var、let和const

let与var类似是用来声明变量的,const用来声明常量(ES5只有全局作用域和函数作用域,没有块级作用域),const也用来声明变量,但是声明的是常量,一旦声明,常量的值就不能改变。它和let一样只在声明的区域内有用。

关于使用letconst规则:

  • 使用let声明的变量可以重新赋值,但是不能在同一作用域内重新声明

  • 使用const声明的变量必须赋值初始化,但是不能在同一作用域类重新声明也无法重新赋值.

  {
      var a = 100;
      let b = 200;
  }
  console.log(a); //100
  console.log(b); //b is not defined -- Error

 {
     var a   = 100;
     const a = 200;
     console.log(a); // 报错
 }

 //const声明对象
 const a = {};
 a.name  = "Zhangsan"; 
 console.log(a.name);   //Zhangsan
 console.log(a);        //Object {name: "Zhangsan"}

总结:let是块级作用域,只在let命令所在的代码块内有效,而var存在变量提升(变量提升代表无论声明在什么地方,都会被视为声明在顶部)

const对象冻结**

const q = Object.freeze({});
q.name  = "Zhangsan";
console.log(q.name);   //undefined
console.log(q);        //Object

模版字符串

使用模板和插入值是在字符串里面输出变量的一种方式。因此,在ES5,我们可以这样组合一个字符串:

var id = 1;
var first = 'g';
var last = 'm';
var name = 'Your name is ' + first + ' ' + last + '.';
var url = 'http://localhost:3000/api/messages/' + id;

在ES6中,我们可以使用新的语法$ {NAME},并把它放在反引号里:

let id = 1;
let first = 'g';
let last = 'm';
let name = `Your name is ${first} ${last}. `;
let url = `http://localhost:3000/api/messages/${id}`;

Multi-line Strings (多行字符串)in ES6

ES6的多行字符串是一个非常实用的功能。在ES5中,我们不得不使用以下方法来表示多行字符串:

var roadPoem = 'Then took the other, as just as fair,nt'
    + 'And having perhaps the better claimnt'
    + 'Because it was grassy and wanted wear,nt'
    + 'Though as for that the passing therent'
    + 'Had worn them really about the same,nt';
var fourAgreements = 'You have the right to be you.n
    You can only be you when you do your best.';

在ES6中,仅仅用反引号就可以解决了:

var roadPoem = `Then took the other, as just as fair,
    And having perhaps the better claim
    Because it was grassy and wanted wear,
    Though as for that the passing there
    Had worn them really about the same,`;
var fourAgreements = `You have the right to be you.
    You can only be you when you do your best.`;

解构赋值

在ES6中,可以使用解构从数组和对象提取值并赋值给独特的变量。

在ES5中是这样:

var person = {name: 'gm', age: 25};
var name = person.name;
var age = person.age;
console.log(name + age);

在ES6,我们可以使用这些语句代替上面的ES5代码:

var person = {name: 'gm', age: 25};
var { name, age } = person;
console.log(name + age);

//数组
const point = [10, 25, -34];
const [x, y, z] = point;
console.log(x, y, z);

...操作符

展开运算符(用三个连续的点 (...) 表示)是 ES6 中的新概念,使你能够将字面量对象展开为多个元素

    let str2 = ['苹果','梨子'];
    console.log(str2);//["苹果", "梨子"]
    console.log(...str2);//苹果 梨子

    const fruits = ["apples", "bananas", "pears"];
    const vegetables = ["corn", "potatoes", "carrots"];
    const produce = [...fruits,...vegetables];
    console.log(produce);

剩余操作符 使用展开运算符将数组展开为多个元素, 使用剩余参数可以将多个元素绑定到一个数组中.

ES5中

function sum() {
  let total = 0;  
  for(const argument of arguments) {
    total += argument;
  }
  return total;
}

ES6中

    fun(a,b,...c){
        console.log(a,b,...c);//...c指展开数组
    }
    fun('苹果','香蕉','橘子','梨子','李子');//苹果 香蕉 橘子 梨子 李子

Enhanced Object Literals (增强的对象字面量)in ES6

使用对象文本可以做许多让人意想不到的事情!通过ES6,我们可以把ES5中的JSON变得更加接近于一个类。
下面是一个典型ES5对象文本,里面有一些方法和属性:

var serviceBase = {port: 3000, url: 'azat.co'},
 getAccounts = function(){return [1,2,3]};
var accountServiceES5 = {
 port: serviceBase.port,
 url: serviceBase.url,
 getAccounts: getAccounts,
 toString: function() {
 return JSON.stringify(this.valueOf());
 },
 getUrl: function() {return "http://" + this.url + ':' + this.port},
 valueOf_1_2_3: getAccounts()
}

如果我们想让它更有意思,我们可以用Object.create从serviceBase继承原型的方法:

var accountServiceES5ObjectCreate = Object.create(serviceBase)
var accountServiceES5ObjectCreate = {
  getAccounts: getAccounts,
  toString: function() {
    return JSON.stringify(this.valueOf());
  },
  getUrl: function() {return "http://" + this.url + ':' + this.port},
  valueOf_1_2_3: getAccounts()
}

我们知道,accountServiceES5ObjectCreate 和accountServiceES5 并不是完全一致的,因为一个对象(accountServiceES5)在proto对象中将有下面这些属性:

new1

为了方便举例,我们将考虑它们的相似处。所以在ES6的对象文本中,既可以直接分配getAccounts: getAccounts,也可以只需用一个getAccounts,此外,我们在这里通过proto(并不是通过’proto’)设置属性,如下所示:

var serviceBase = {port: 3000, url: 'azat.co'},
getAccounts = function(){return [1,2,3]};
var accountService = {
 __proto__: serviceBase,
 getAccounts,

另外,我们可以调用super防范,以及使用动态key值(valueOf_1_2_3):

 toString() {
 return JSON.stringify((super.valueOf()));
 },
 getUrl() {return "http://" + this.url + ':' + this.port},
 [ 'valueOf_' + getAccounts().join('_') ]: getAccounts()
};
console.log(accountService)

函数

定义函数

我们先来看一个基本的新特性,在javascript中,定义函数需要关键字function,但是在es6中,还有更先进的写法,我们来看:

es6写法:

var human = {
    breathe(name) {   //不需要function也能定义breathe函数。
        console.log(name + ' is breathing...');
    }
};
human.breathe('jarson');   //输出 ‘jarson is breathing...’

转成js代码:

var human = {
    breathe: function(name) {
        console.log(name + 'is breathing...');
    }
};
human.breathe('jarson');

函数默认参数

es5中

    var link = function (height, color, url) {
    var height = height || 50;
    var color = color || 'red';
    var url = url || 'http://azat.co';
    ...
    }

es6为参数提供了默认值。在定义函数时便初始化了这个参数,直接看代码。

    var link = function(height = 50, color = 'red', url = 'http://azat.co') {
      ...
    }

箭头函数

ES6之前,使用普通函数把其中每个名字转换为大写形式:

const upperizedNames = ['Farrin', 'Kagure', 'Asser'].map(function(name) { 
  return name.toUpperCase();
});

箭头函数表示:

const upperizedNames = ['Farrin', 'Kagure', 'Asser'].map(
  name => name.toUpperCase()
);

普通函数可以是函数声明或者函数表达式, 但是箭头函数始终都是表达式, 全程是箭头函数表达式, 因此因此仅在表达式有效时才能使用,包括:

  • 存储在变量中,

  • 当做参数传递给函数,

  • 存储在对象的属性中。

const greet = name => `Hello ${name}!`;

可以如下调用:

greet('Asser');

如果函数的参数只有一个,不需要使用()包起来,但是只有一个或者多个, 则必须需要将参数列表放在圆括号内:

// 空参数列表需要括号
const sayHi = () => console.log('Hello Udacity Student!');

// 多个参数需要括号
const orderIceCream = (flavor, cone) => console.log(`Here's your ${flavor} ice cream in a ${cone} cone.`);
orderIceCream('chocolate', 'waffle');

一般箭头函数都只有一个表达式作为函数主题:

const upperizedNames = ['Farrin', 'Kagure', 'Asser'].map(
  name => name.toUpperCase()
);

这种函数表达式形式称为简写主体语法:

  • 在函数主体周围没有花括号,

  • 自动返回表达式

但是如果箭头函数的主体内需要多行代码, 则需要使用常规主体语法:

  • 它将函数主体放在花括号内

  • 需要使用 return 语句来返回内容。

const upperizedNames = ['Farrin', 'Kagure', 'Asser'].map( name => {
  name = name.toUpperCase();
  return `${name} has ${name.length} characters in their name`;
});

有了箭头函数在ES6中, 我们就不必用that = this或 self = this 或 _this = this 或.bind(this)。例如,下面的代码用ES5就不是很优雅:以前我们使用闭包,this总是预期之外地产生改变,而箭头函数的迷人之处在于,现在你的this可以按照你的预期使用了,身处箭头函数里面,this还是原来的this。

var _this = this;
$('.btn').click(function(event){
  _this.sendData();
})

在ES6中就不需要用 _this = this:

$('.btn').click((event) =>{
  this.sendData();
})

下面这是一个另外的例子,我们通过call传递文本给logUpperCase() 函数在ES5中:

var logUpperCase = function() {
  var _this = this;

  this.string = this.string.toUpperCase();
  return function () {
    return console.log(_this.string);
  }
}

logUpperCase.call({ string: 'ES6 rocks' })();

而在ES6,我们并不需要用_this浪费时间:

var logUpperCase = function() {
  this.string = this.string.toUpperCase();
  return () => console.log(this.string);
}
logUpperCase.call({ string: 'ES6 rocks' })();

闭包解释

闭包,官方对闭包的解释是:一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。闭包的特点:
  1. 作为一个函数变量的一个引用,当函数返回时,其处于激活状态。
  2. 一个闭包就是当一个函数返回时,一个没有释放资源的栈区。
  简单的说,Javascript允许使用内部函数---即函数定义和函数表达式位于另一个函数的函数体内。而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量、参数和声明的其他内部函数。当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包。

总结:闭包指的是:能够访问另一个函数作用域的变量的函数。清晰的讲:闭包就是一个函数,这个函数能够访问其他函数的作用域中的变量。

function outer() {
     var  a = '变量1'
     var  inner = function () {
            console.info(a)
     }
    return inner    // inner 就是一个闭包函数,因为他能够访问到outer函数的作用域
}

坑点1: 引用的变量可能发生变化

function outer() {
      var result = [];
      for (var i = 0; i<10; i++){
        result.[i] = function () {
            console.info(i)
        }
     }
     return result
}

看样子result每个闭包函数对打印对应数字,1,2,3,4,...,10, 实际不是,因为每个闭包函数访问变量i是outer执行环境下的变量i,随着循环的结束,i已经变成10了,所以执行每个闭包函数,结果打印10, 10, ..., 10
怎么解决这个问题呢?

function outer() {
      var result = [];
      for (var i = 0; i<10; i++){
        result.[i] = function (num) {
             return function() {
                   console.info(num);    // 此时访问的num,是上层函数执行环境的num,数组有10个函数对象,每个对象的执行环境下的number都不一样
             }
        }(i)
     }
     return result
}

坑点2: this指向问题

var object = {
     name: ''object",
     getName: function() {
        return function() {
             console.info(this.name)
        }
    }
}
object.getName()()    // underfined
// 因为里面的闭包函数是在window作用域下执行的,也就是说,this指向windows

坑点3:内存泄露问题

function  showId() {
    var el = document.getElementById("app")
    el.onclick = function(){
      aler(el.id)   // 这样会导致闭包引用外层的el,当执行完showId后,el无法释放
    }
}

// 改成下面
function  showId() {
    var el = document.getElementById("app")
    var id  = el.id
    el.onclick = function(){
      aler(id)   // 这样会导致闭包引用外层的el,当执行完showId后,el无法释放
    }
    el = null    // 主动释放el
}

技巧1: 用闭包解决递归调用问题

function  factorial(num) {
   if(num<= 1) {
       return 1;
   } else {
      return num * factorial(num-1)
   }
}
var anotherFactorial = factorial
factorial = null
anotherFactorial(4)   // 报错 ,因为最好是return num* arguments.callee(num-1),arguments.callee指向当前执行函数,但是在严格模式下不能使用该属性也会报错,所以借助闭包来实现


// 使用闭包实现递归
function newFactorial = (function f(num){
    if(num<1) {return 1}
    else {
       return num* f(num-1)
    }
}) //这样就没有问题了,实际上起作用的是闭包函数f,而不是外面的函数newFactorial

** 技巧2:用闭包模仿块级作用域**
es6没出来之前,用var定义变量存在变量提升问题,eg:

for(var i=0; i<10; i++){
    console.info(i)
}
alert(i)  // 变量提升,弹出10

//为了避免i的提升可以这样做
(function () {
    for(var i=0; i<10; i++){
         console.info(i)
    }
})()
alert(i)   // underfined   因为i随着闭包函数的退出,执行环境销毁,变量回收

当然现在大多用es6的let 和const 定义

Class、 extends、 super

ES6提供了更接近传统语言的写法,引入了Class(类)这个概念。新的class写法让对象原型的写法更加清晰、更像面向对象编程的语法,也更加通俗易懂。

ES5写法:

function Human(name) {
    this.name = name;
    this.breathe = function() {
        console.log(this.name + ' is breathing');
    }
}
var man = new Human('jarson');
man.breathe();    //jarson is breathing

ES6中

class Human {
    constructor(name) {
        this.name = name;
    }
    breathe() {
        console.log(this.name + " is breathing");
    }
} 
var man = new Human("jarson");
man.breathe();    //jarson is breathing

extends用法

class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
}

class ColorPoint extends Point {
  constructor(x, y, color) {
    this.color = color; // ReferenceError
    super(x, y);
    this.color = color; // 正确
  }
}

在子类的构造函数中,只有调用super之后,才可以使用this关键字,否则会报错。这是因为子类实例的构建,是基于对父类实例加工,只有super方法才能返回父类实例。父类的静态方法,也会被子类继承。

注意,super虽然代表了父类Point的构造函数,但是返回的是子类ColorPoint的实例,即super内部的this指的是ColorPoint,因此super()在这里相当于Point.prototype.constructor.call(this)。

super这个关键字,既可以当作函数使用,也可以当作对象使用。在这两种情况下,它的用法完全不同。
作为函数时,super()只能用在子类的构造函数之中,用在其他地方就会报错。

    class A {}
    class B extends A {
      m() {
         super(); // 报错
      }
    }

第二种情况,super作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类。

     class A {
        p() {
         return 2;
       }
     }
     class B extends A {
        constructor() {
          super();
          console.log(super.p()); // 2
        }
     }
     let b = new B();

上面代码中,子类B当中的super.p()就是将super当作一个对象使用。这时,super在普通方法之中,指向A.prototype,所以super.p()就相当于A.prototype.p()。这里需要注意,由于super指向父类的原型对象,所以定义在父类实例上的方法或属性,是无法通过super调用的。

Modules(模块)

众所周知,在ES6以前JavaScript并不支持本地的模块。人们想出了AMD,RequireJS,CommonJS以及其它解决方法。现在ES6中可以用模块import 和export 操作了。
在ES5中,你可以在 <script>中直接写可以运行的代码(简称IIFE),或者一些库像AMD。然而在ES6中,你可以用export导入你的类。下面举个例子,在ES5中,module.js有port变量和getAccounts 方法:

module.exports = {
  port: 3000,
  getAccounts: function() {
    ...
  }
}

在ES5中,main.js需要依赖require(‘module’) 导入module.js:

var service = require('module.js');
console.log(service.port); // 3000

但在ES6中,我们将用export and import。例如,这是我们用ES6 写的module.js文件库:

export var port = 3000;
export function getAccounts(url) {
  ...
}

如果用ES6来导入到文件main.js中,我们需用import {name} from ‘my-module’语法,例如:

import {port, getAccounts} from 'module';
console.log(port); // 3000

或者我们可以在main.js中把整个模块导入, 并命名为 service:

import * as service from 'module';
console.log(service.port); // 3000

Promises

Promises 是一个有争议的话题。因此有许多略微不同的promise 实现语法。Q,bluebird,deferred.js,vow, avow, jquery 一些可以列出名字的。也有人说我们不需要promises,仅仅使用异步,生成器,回调等就够了。但令人高兴的是,在ES6中有标准的Promise实现。

学习链接:https://blog.csdn.net/yaocong1993/article/details/85252151

网络请求事例

es5中

function zpost(url,param,doPost){
    if(!url.startWith("http://"))
        url = getSite() + "/" + url;
    $.ajax({
        type: 'POST',
        url: url,
        data: param,
        dataType: 'html',
        timeout: 30000,
        success: function(data){
            doPost(data);
        },
        error: function(xhr, type){
            hideLoading();
            zalert("网络不给力!");
        }
    });
}

es6中

this.$http('/api/getData').then((res) => {
res = res.data;
this.dataList = res.result;
}).catch((err) => {
...
});

下面是一个简单的用setTimeout()实现的异步延迟加载函数:

setTimeout(function(){
  console.log('Yay!');
}, 1000);

在ES6中,我们可以用promise重写:

var wait1000 =  new Promise(function(resolve, reject) {
  setTimeout(resolve, 1000);
}).then(function() {
  console.log('Yay!');
});

或者用ES6的箭头函数:

var wait1000 =  new Promise((resolve, reject)=> {
  setTimeout(resolve, 1000);
}).then(()=> {
  console.log('Yay!');
});

到目前为止,代码的行数从三行增加到五行,并没有任何明显的好处。确实,如果我们有更多的嵌套逻辑在setTimeout()回调函数中,我们将发现更多好处:

setTimeout(function(){
  console.log('Yay!');
  setTimeout(function(){
    console.log('Wheeyee!');
  }, 1000)
}, 1000);

在ES6中我们可以用promises重写:

var wait1000 =  ()=> new Promise((resolve, reject)=> {setTimeout(resolve, 1000)});
wait1000()
    .then(function() {
        console.log('Yay!')
        return wait1000()
    })
    .then(function() {
        console.log('Wheeyee!')
    });

Generator生成器函数

ES6中非常受关注的的一个功能,能够在函数中间暂停,一次或者多次,并且之后恢复执行,在它暂停的期间允许其他代码执行,并可以用其实现异步。

简单使用

在异步编程中,还有一种常用的解决方案,它就是Generator生成器函数。顾名思义,它是一个生成器,它也是一个状态机,内部拥有值及相关的状态,生成器返回一个迭代器Iterator对象,我们可以通过这个迭代器,手动地遍历相关的值、状态,保证正确的执行顺序。

function *foo(x) {
    var y = 2 * (yield (x + 1));
    var z = yield (y / 3);
    return (x + y + z);
}

var it = foo( 5 );

console.log( it.next() );       // { value:6, done:false }
console.log( it.next( 12 ) );   // { value:8, done:false }
console.log( it.next( 13 ) );   // { value:42, done:true }

generator能实现好多功能,如配合for...of使用,实现异步等等

function* showWords() {
    yield 'one';
    yield 'two';
    return 'three';
}

var show = showWords();

show.next() // {done: false, value: "one"}
show.next() // {done: false, value: "two"}
show.next() // {done: true, value: "three"}
show.next() // {done: true, value: undefined}

如上代码,定义了一个showWords的生成器函数,调用之后返回了一个迭代器对象(即show),调用next方法后,函数内执行第一条yield语句,输出当前的状态done(迭代器是否遍历完成)以及相应值(一般为yield关键字后面的运算结果),每调用一次next,则执行一次yield语句,并在该处暂停,return完成之后,就退出了生成器函数,后续如果还有yield操作就不再执行了

yield和yield*

function* showWords() {
    yield 'one';
    yield showNumbers();
    return 'three';
}

function* showNumbers() {
    yield 10 + 1;
    yield 12;
}

var show = showWords();
show.next() // {done: false, value: "one"}
show.next() // {done: false, value: showNumbers}
show.next() // {done: true, value: "three"}
show.next() // {done: true, value: undefined}

增添了一个生成器函数,我们想在showWords中调用一次,简单的 yield showNumbers()之后发现并没有执行函数里面的yield 10+1,因为yield只能原封不动地返回右边运算后值,但现在的showNumbers()不是一般的函数调用,返回的是迭代器对象,所以换个yield* 让它自动遍历进该对象

注意的是,这yield和yield 只能在generator函数内部使用,一般的函数内使用会报错*

next()调用中的传参

function* showNumbers() {
    var one = yield 1;
    var two = yield 2 * one;
    yield 3 * two;
}

var show = showNumbers();

show.next().value // 1
show.next().value // NaN
show.next(2).value // 6

第一次调用next之后返回值one为1,但在第二次调用next的时候one其实是undefined的,因为generator不会自动保存相应变量值,我们需要手动的指定,这时two值为NaN,在第三次调用next的时候执行到yield 3 * two,通过传参将上次yield返回值two设为2

引用链接:https://www.cnblogs.com/imwtr/p/5913294.html , https://www.jianshu.com/p/393d2a203977

for...of循环代替.next()

除了使用.next()方法遍历迭代器对象外,通过ES6提供的新循环方式for...of也可遍历,但与next不同的是,它会忽略return返回的值,如

const fruits = ['apple','coconut','mango','durian'];
//for循环数组,通过下标取得每一项的值
for (let i = 0; i < fruits.length; i++) {
    console.log(fruits[i]);
}

//数组的forEach方法,相对for循环语法更简单
fruits.forEach(fruit => {
    console.log(fruit);
})

//forEach有个问题是不能终止循环
fruits.forEach(fruit => {
    if(fruit === 'mango' ){
        break;                        //Illegal break statement
    }
    console.log(fruit);
})

//for...in循环,遍历数组对象的属性,MDN不推荐使用for...in遍历数组
//for...in循环会打印出非数字属性
const fruits = ['apple','coconut','mango','durian'];
fruits.fav = 'my favorite fruit';

for(let index in fruits){
    console.log(fruits[index]);   //...my favorite fruit
}

function* showNumbers() {
    yield 1;
    yield 2;
    return 3;
}

var show = showNumbers();

for (var n of show) {
    console.log(n) // 1 2
}

const fruits = ['apple','coconut','mango','durian'];
fruits.fav = 'my favorite fruit';

//ES6中的for...of循环,遍历属性值
for(let fruit of fruits){
    console.log(fruit);
}

//支持终止循环,也不会遍历非数字属性
for(let fruit of fruits){
    if(fruit === 'mango' ){
        break;
    }
    console.log(fruit);      //apple coconut durian
}

function* showNumbers() {
    yield 1;
    yield 2;
    return 3;
}

var show = showNumbers();

[...show] // [1, 2, length: 2]

学习链接:http://es6.ruanyifeng.com/

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

推荐阅读更多精彩内容

  • 一、ES6简介 ​ 历时将近6年的时间来制定的新 ECMAScript 标准 ECMAScript 6(亦称 ...
    一岁一枯荣_阅读 5,959评论 8 25
  • 本文为阮一峰大神的《ECMAScript 6 入门》的个人版提纯! babel babel负责将JS高级语法转义,...
    Devildi已被占用阅读 1,927评论 0 4
  • 转载请注明出处 原文连接 http://blog.huanghanlian.com/article/5c7aa6c...
    深沉的简单阅读 1,810评论 0 40
  • 以下内容是我在学习和研究ES6时,对ES6的特性、重点和注意事项的提取、精练和总结,可以做为ES6特性的字典;在本...
    科研者阅读 3,027评论 2 9
  • 第一章:块级作用域绑定 块级声明 1.var声明及变量提升机制:在函数作用域或者全局作用域中通过关键字var声明的...
    BeADre_wang阅读 760评论 0 0