ECMAScript 6入門筆記

1. 作用域變量

作用域就是變量的作用范圍奸汇。也就是你聲明一個(gè)變量以后,這個(gè)變量可以在什么場(chǎng)合下使用往声。以前的JavaScript只有全局作用域擂找,和函數(shù)作用域。

1.1 var的問(wèn)題

1.var 沒(méi)有塊級(jí)作用域浩销,定義后在當(dāng)前包中都都可以訪問(wèn)贯涎,如果變量名重復(fù),就會(huì)覆蓋前面定義的變量慢洋,并且很可以被他人修改塘雳。

if(true){
    var a = "a"; //期望a是某一個(gè)值
}
console.log(a);

<br />2.var 在for循環(huán)標(biāo)記變量共享,一般在循環(huán)中會(huì)使用的i會(huì)被共享普筹,其本質(zhì)也是由于沒(méi)有塊級(jí)作用域造成的<br />

for (var i = 0; i < 3; i++) {
     setTimeout(function () {
         alert(i);
     }, 0);
 }
 
 // 結(jié)果就是 彈窗三次 3
 
 for ( i = 0; i < 3; i++) {
     setTimeout(function () {
         alert(i);
     }, 0);
 }
 
 // 結(jié)果就是 彈窗三次 0-2

1.2 塊級(jí)作用域

在用var定義變量的時(shí)候败明,變量通過(guò)閉包進(jìn)行隔離的,現(xiàn)在用了let斑芜,不僅僅可以通過(guò)閉包隔離肩刃,還可以增加了一些塊級(jí)作用域隔離。塊級(jí)作用用一組大括號(hào)定義一個(gè)快,使用let定義的變量字啊大括號(hào)的外面是訪問(wèn)不到的盈包。

1.2.1 實(shí)現(xiàn)會(huì)計(jì)作用域

if(ture){
    let name = 'wjh'
}

consloe.log('name'); // ReferenceError: name is not defined

1.2.2 不會(huì)污染全局對(duì)象

if(ture){
    let name = 'wjh'
}
console.log(window.name); // undefined

1.2.3 for 循環(huán)中也可以使用i

// 嵌套循環(huán)不會(huì)相互影響
for (let i = 0; i < 3; i++) {
   console.log("out", i);
   for (let i = 0; i < 2; i++) {
   console.log("in", i);
  }
}

// 結(jié)果 out 0 in 0 in 1 out 1 in 0 in 1 out 2 in 0 in 1

1.2.4 重復(fù)定義會(huì)報(bào)錯(cuò)

if(ture){
    let a = 1;
  let a = 2; //Identifier 'a'
}

1.2.5 不存在變量的預(yù)解釋

for(let i = 0;i<2;i++){
    console.log('inner',i);
  let i =100;
}

// 結(jié)果 i is not defined

1.2.6 閉包的新寫法

;(function(){

})();

現(xiàn)在

{

}

2. 常量

使用 const 我們可以聲明一個(gè)常量沸呐,一旦聲明之后,就不可以更改呢燥。

2.1 常量不能重新賦值

const MY_NAME = 'wjw';
MY_NAME = 'wjw2';//Assignment to constant variable

2.2 變量可以改變

注意const限制的是不能給變量重新賦值崭添,而變量的值本身是可以改變的,下面的操作是可以的

const names = ['wjw1'];
names.push('wjw2');
console.log(names);

2.3 不同的塊級(jí)作用域可以多次定義

const A = "0";
{
    const A = "A";
    console.log(A)
}
{
    const A = "B";
    console.log(A)
}
console.log(A)

// 結(jié)果 A B 0

3. 解構(gòu)

3.1 解構(gòu)數(shù)組

解構(gòu)意思就是分解一個(gè)東西的結(jié)構(gòu),可以用一種類似數(shù)組的方式定義N個(gè)變量,可以將一個(gè)數(shù)組中的值按照規(guī)則賦值過(guò)去叛氨。<br />

var [name,age]=['wjh',8];
console.log(name,age);

3.2 嵌套賦值

let [x,[y],z]=[1,[2.1]];
console.log(x,y,z);

let [x,[y,z]] = [1,[2.1,2.2]];
console.log(x,y,z);

let [json,arr,num] = [{name:'wjw'},[1,2],3];
console.log(json,arr,num);

// 1 2.1 undefined 1 2.1 2.2 { name: 'wjw' } [ 1, 2 ] 3

3.3 省略賦值

let [,,x]=[1,2,3]
console.log(x);

3.4 解構(gòu)對(duì)象

對(duì)象也可以被解構(gòu)

var obj = {name:'wjw',age:8};
//對(duì)象里的name屬性的值會(huì)交給name這個(gè)變量呼渣,age的值會(huì)交給age這個(gè)變量
var {name,age} = obj
//對(duì)象里的name屬性的值會(huì)交給myname這個(gè)變量,age的值會(huì)交給myage這個(gè)變量
let {name: myname, age: myage} = obj;
console.log(name,age,myname,myage);

3.5 默認(rèn)值

在賦值和傳參的時(shí)候可以使用默認(rèn)值

let [a='a',b='b',c=new Error('C必須指定')] = [1, , 3];
console.log(a,b,c);

function ajax(options){
    var method = options.method || "get";
  var data = options.data || {};
}

function ajax(method='get',data){
    console.log(arguments);
}

ajax({
    method:'post',
  data:{'name':'wjh'}
})

4. 字符串

4.1 模板字符串

模板字符串用反應(yīng)號(hào)(數(shù)字1左邊的那個(gè)建)包含寞埠,用${}括起來(lái)<br /><br />

var name = 'wjw',age = 8;
let desc = `${name} is ${age} old!`;
console.log(desc);

//所有模板字符串的空格和換行屁置,都是被保留的
var str = `<ul>
<li>a</li>
<li>b</li>
</ul>`;
console.log(str);

其中的變量會(huì)用變量的值替換掉

function replace(desc){
    return desc.replace(/\$\{([^}]+)\}/g,function(matched,key){
    return eval(key);
  });
}

4.2 帶標(biāo)簽的模板字符串

可以在模板字符串的前面添加一個(gè)標(biāo)簽,這個(gè)標(biāo)簽可以去處理模板字符串 標(biāo)簽其實(shí)就是一個(gè)函數(shù),函數(shù)可以接收兩個(gè)參數(shù),一個(gè)是 strings 就是模板字符串里的每個(gè)部分的字符 還有一個(gè)參數(shù)可以使用rest的形式values,這個(gè)參數(shù)里面是模板字符串里的值仁连。

var name = 'wjh',age = 8;
function desc(strings,...values){
    console.log(strings,values);
}
desc`${name} is ${age} old!`;

字符串新方法

  • includes():返回布爾值蓝角,表示是否找到了參數(shù)字符串。
  • startsWith():返回布爾值饭冬,表示參數(shù)字符串是否在源字符串的頭部使鹅。
  • endsWith():返回布爾值,表示參數(shù)字符串是否在源字符串的尾部昌抠。
var s = 'wjh';
s.startsWith('w') // true
s.endsWith('h') // true
s.includes('j') // true

第二個(gè)參數(shù)患朱,表示開(kāi)始搜索的位置

var s = 'wjh';
console.log(s.startsWith('j',2)); // true
console.log(s.endsWith('j',2)); // true
console.log(s.includes('j',2)); // false

endsWith的行為與其他其他方法有所不同。它針對(duì)前n個(gè)字符炊苫,而其他方法是從第幾位開(kāi)始到字符串結(jié)束

4.4 repeat

repeat 方法返回一個(gè)新字符串裁厅,表示將原字符串重復(fù)n次。<br /><br />

 'x'.repeat(3);
 'x'.repeat(0);

5. 函數(shù)

5.1 默認(rèn)參數(shù)

可以給定義的函數(shù)接收的參數(shù)設(shè)置默認(rèn)的值 在執(zhí)行這個(gè)函數(shù)的時(shí)候劝评,如果不指定函數(shù)的參數(shù)的值姐直,就會(huì)使用參數(shù)的這些默認(rèn)的值。

function ajax(url,method='GET',dataType="json"){
  console.log(url);
  console.log(method);
  console.log(dataType);
}

5.2 展開(kāi)操作符

把...放在數(shù)組前面可以把一個(gè)數(shù)組進(jìn)行展開(kāi)蒋畜,可以把一個(gè)函數(shù)而不需要使用apply<br /><br />

//傳入?yún)?shù)
let print = function(a,b,c){
    console.log(a,b,c);
}
print([1,2,3]);
print(...[1,2,3]);

// 可以替代apply
var m1 = Math.max.apply(null, [8, 9, 4, 1]);
var m2 = Math.max(...[8, 9, 4, 1]);

// 可以替代concat
var arr1 = [1, 3];
var arr2 = [3, 5];
var arr3 = arr1.concat(arr2);
var arr4 = [...arr1, ...arr2];
console.log(arr3,arr4);

//類數(shù)組的轉(zhuǎn)數(shù)組
function max(a,b,c) {
    console.log(Math.max(...arguments));
}
max(1, 3, 4);

5.3 剩余操作符

剩余操作符可以把其余參數(shù)的值放在一個(gè)叫做b的數(shù)組里

let rest = function(a,...rest){
    console.log(a,rest);
}
rest(1,2,3);

5.4 解構(gòu)參數(shù)

let destruct = function({name,age}){
    console.log(name,age);
}
destruct({name:'wjh',age:10})

5.6 箭頭函數(shù)

箭頭函數(shù)簡(jiǎn)化了函數(shù)的定義方式

[1,2,3].forEach(val=>console.log(val));

輸入?yún)?shù)如果多于一個(gè)要用()包含声畏,函數(shù)體如果有多條語(yǔ)句需要用{}包起來(lái)

箭頭函數(shù)根本沒(méi)有自己的this,導(dǎo)致內(nèi)部的this就是外層代碼塊的this姻成。 正是因?yàn)樗鼪](méi)有this插龄,從而避免了this指向的問(wèn)題。

var person = {
    name:'wjh',
    getName:function(){
-        setTimeout(function(){console.log(this);},1000); //在瀏覽器執(zhí)行的話this指向window
+        setTimeout(() => console.log(this),1000);//在瀏覽器執(zhí)行的話this指向person
    }
}
person.getName();

6. 數(shù)組的新方法

// 相同的陣列
var people = [
  {
    name : 'Casper' ,
    like : '鍋燒意面' ,
    age : 18
  },
  {
    name : 'Wang' ,
    like : '炒面' ,
    age : 24
  },
  {
    name : 'Bobo' ,
    like : '蘿卜泥' ,
    age : 1
  },
  {
    name : '鹵蛋' ,
    like : '蘿卜泥' ,
    age : 3
  }
];

6.1 Array.prototype.filter()

filter() 會(huì)回傳一個(gè)陣列科展,其條件是return 后方為true 的物件均牢,很適合用在搜尋符合條件的資料。

var filterEmpty = people.filter( function ( item, index, array ) {
});
console.log(filterEmpty);     //沒(méi)有條件才睹,會(huì)是一個(gè)空陣列

var filterAgeThan5 = people.filter( function ( item, index, array ) {
  return item.age > 5 ;        //取得大于五歲的   如果這邊符合條件 只要為ture即可
});
console .log(filterAgeThan5);    // Casper, Wang這兩個(gè)物件

6.2 Array.prototype.find()

find()與filter()很像徘跪,但find() 只會(huì)回傳一次值甘邀,且是第一次為true的值。

var findEmpty = people.find( function ( item, index, array ) {
});
console .log(findEmpty);           //沒(méi)有條件垮庐,會(huì)是undefined

var findAgeThan5 = people.find( function ( item, index, array ) {
  return item.age > 5 ;            //取得大于五歲的
});

console .log(findAgeThan5);        //雖然答案有兩個(gè)松邪,但只會(huì)回傳Casper這一個(gè)物件
var findLike = people.find( function ( item, index, array ) {
  return item.like === '蘿卜泥' ;   //取得陣列l(wèi)ike === '蘿卜泥'
});
console .log(findLike);            //雖然答案有兩個(gè),但只會(huì)回傳第一個(gè)Bobo物件

6.3 Array.prototype.forEach()

forEach 是這幾個(gè)陣列函式最單純的一個(gè)哨查,不會(huì)額外回傳值逗抑,只單純執(zhí)行每個(gè)陣列內(nèi)的物件或值。

var forEachIt = people.forEach( function ( item, index, array ) {
  console .log(item, index, array); //物件,索引,全部陣列
  return item;                      // forEach沒(méi)在return的寒亥,所以這邊寫了也沒(méi)用
});

console .log(forEachIt);             // undefined

people.forEach( function ( item, index, array ) {
  item.age = item.age + 1 ;          // forEach就如同for邮府,不過(guò)寫法更容易
});
console .log(people);                //全部age + 1

6.4 Array.prototype.map()

使用map() 時(shí)他需要回傳一個(gè)值,他會(huì)透過(guò)函式內(nèi)所回傳的值組合成一個(gè)陣列溉奕。
如果不回傳則是 undefined
回傳數(shù)量等于原始陣列的長(zhǎng)度
這很適合將原始的變數(shù)運(yùn)算后重新組合一個(gè)新的陣列褂傀。

var mapEmpty = people.map( function ( item, index, array ) {
});
console .log(mapEmpty);     // [undefined, undefined, undefined, undefined]

var mapAgeThan5 = people.map( function ( item, index, array ) {
  return item.age > 5 ;     //比較大于五歲的
});
console .log(mapAgeThan5); // [true, true, false, false]

var mapAgeThan5_2 = people.map( function ( item, index, array ) {
  // 錯(cuò)誤示范
  if (item.age > 5 ) {
    return item;               //回傳大于五歲的
  }
  return  false ;                //別以為空的或是false就不會(huì)回傳
});
console .log(mapAgeThan5_2);    // [{name: 'Casper'...}, {name: 'Wang'...}, false, false]
var mapEat = people.map( function ( item, index, array ) {
  if (item.like !== '蘿卜泥' ) {
    return  ` ${item.like}好吃` ;
  } else {
    return  ` ${item.like}不好吃` ;
  }
});
console .log(mapEat);           // ["鍋燒意面好吃", "炒面好吃", "蘿卜泥不好吃", "蘿卜泥不好吃"]

6.5 Array.prototype.every()

every()可以檢查所有的陣列是否符合條件,這僅會(huì)回傳一個(gè)值trueor false腐宋,可以用來(lái)檢查陣列中的內(nèi)容是否符合特定條件紊服。

var ans = array.every( function ( item, index, array ) {
  console .log(item, index, array); //物件,索引,全部陣列
  return item.age > 10  //當(dāng)全部age大于10才能回傳true
});
console .log(ans); // false:只要有部分不符合檀轨,則為false

var ans2 = array.every( function ( item, index, array ) {
  return item.age < 25
});
console .log(ans2); // true:全部age都小于25

6.6 Array.prototype.some()

some() 與every() 非常接近胸竞,都是回傳true or false,差異僅在every() 需完全符合参萄,some() 僅需要部分符合卫枝。

var ans = people.some( function ( item, index, array ) {
  return item.age > 10  //當(dāng)全部age大于10才能回傳true
});
console .log(ans);   // true:只要有部分符合,則為true

var ans2 = people.some( function ( item, index, array ) {
  return item.age < 25
});
console .log(ans2); // true:只要有部分符合讹挎,則為true  

var ans2 = people.some( function ( item, index, array ) {
  return item.age > 25
});
console .log(ans2); // false:全部都不符合則為false

6.7 Array.prototype.reduce()

reduce() 和其他幾個(gè)差異就很大了校赤,他可以與前一個(gè)回傳的值再次作運(yùn)算,參數(shù)包含以下:
accumulator: 前一個(gè)參數(shù)筒溃,如果是第一個(gè)陣列的話马篮,值是以另外傳入或初始化的值
currentValue: 當(dāng)前變數(shù)
currentIndex: 當(dāng)前索引
array: 全部陣列

var reduceEmpty = people.reduce( function ( accumulator, currentValue, currentIndex, array ) {
});
console .log(reduceEmpty);                  //沒(méi)有條件,會(huì)是undefined

var reducePlus = people.reduce( function ( accumulator, currentValue, currentIndex, array ) {
  // 分別為前一個(gè)回傳值, 目前值, 當(dāng)前索引值
  console .log(accumulator, currentValue, currentIndex);
  return accumulator + currentValue.age;   //與前一個(gè)值相加
}, 0 );                                     //傳入初始化值為0
console .log(reducePlus);                   //總和為46

var reducePlus = people.reduce( function ( accumulator, currentValue, currentIndex, array ) {
  console .log( 'reduce' , accumulator, currentValue, currentIndex)
  return  Math .max( accumulator, currentValue.age ); //與前一個(gè)值比較哪個(gè)大
}, 0 );
console .log(reducePlus);                   //最大值為24

7. 對(duì)象

7.1 對(duì)象字面量

如果你想在對(duì)象里添加跟變量名一樣的屬性怜奖,并且屬性的值就是變量表示的值就可以直接在對(duì)象里加上這些屬性

let name = 'wjh';
let age = 8;
let getName = function(){
        console.log(this.name)
}
let person ={
        name,
    age,
    getName
}
person.getName();

7.2 Object.is

對(duì)比兩個(gè)值是否相等

console.log(Object.is(NaN,NaN));

7.3 Object.assign

把多個(gè)對(duì)象的屬性復(fù)制到一個(gè)對(duì)象中浑测,第一個(gè)參數(shù)是復(fù)制的對(duì)象,從第二個(gè)參數(shù)開(kāi)始往后歪玲,都是復(fù)制的源對(duì)象

var nameObj = {name:'wjh'}
var ageObj = {age:8};
var obj = {};
Object.assign(obj,nameObj,ageObj);
console.log(obj);

//克隆對(duì)象
function clone(obj){
    return Object.assgin({},obj);
}

7.4 Object.setPrototypeOf

將一個(gè)指定的對(duì)象原型設(shè)置為另一個(gè)對(duì)象或者null

var obj1 = {name:'wjh1'};
var obj2 = {name:'wjh2'};
var obj = {};
Object.setPrototypeOf(obj,obj1);
console.log(obj.name);
console.log(Object.getPrototypeOf(obj));
Object.setProtoypeOF(obj,obj2);
console.log(obj.name);
console.log(Object.getPrototypeOf(obj));

7.5 proto

直接對(duì)象表達(dá)式中設(shè)置prototype

var obj1 = {name:'wjh'};
var obj3 = {
    _proto_:obj1
} 
console.log(obj3.name);
console.log(Object.getPrototypeOf(obj3));

7.6 super

通過(guò)super可以調(diào)用protype上的屬性或方法

let person ={
    eat(){
    return 'milk';
  }
}
let student = {
    _proto_:person,
  eat(){
    return super.eat()+'bead'
  }
}
console.log(student.eat());

8. 類

8.1 class

使用 class 這個(gè)關(guān)鍵詞定義一個(gè)類迁央,基于這個(gè)創(chuàng)建實(shí)例以后就會(huì)創(chuàng)建 constructor 方法,此方法可以用來(lái)初始化

class Person{
    constructor(name){
    this.name = name;
  }
  
  getName(){
        console.log(this.name)  
  }

}

let person = new Person('wjh');
person.getName();

8.2 get與set

getter 可以用來(lái)獲取屬性,setter 可以去設(shè)置屬性

class Person {
    constructor(){
    this.hobbies = [];
  }
  set hobby(hobby){
    this.hobbies.push(hobby);
  }
  get hobby(){
    return this.hobbies;
  }
}
let person = new Person();
person.hobby = 'aa';
person.hobby = 'bb';
console.log(person.hobby)

8.3 靜態(tài)方法-static

在類里面添加靜態(tài)的方法可以使用static 這個(gè)關(guān)鍵詞滥崩,靜態(tài)方法就是不需要實(shí)例化類就能使用的方法

class Person{
    static add(a,b){
    return a+b;
  }
}
console.log(Person.add(1,x));

8.4 繼承extends

一個(gè)類可以繼承其他的類里的東西

class Person{
    constructor(name){
    this.name = name;
  }
}

class Teacher extends Person{
    constructor(name,age){
    super(name);
    this.age = age;
  }
}

var teacher = Teacher('wjh',8);
console.log(teacher.name,teacher.age)

9. 生成器(Generator)與迭代器(Iterator)

Generator 是一個(gè)特殊的函數(shù)岖圈,執(zhí)行它會(huì)返回一個(gè)Iterator對(duì)象。通過(guò)遍歷迭代器钙皮,Generator函數(shù)運(yùn)行后悔返回遍歷器對(duì)象蜂科,而不是函數(shù)的返回值顽决。

9.1 Iterators模擬

迭代器有一個(gè)next方法,每次執(zhí)行的時(shí)候會(huì)返回一個(gè)對(duì)象 對(duì)象里面有兩個(gè)函數(shù)导匣,一個(gè)是value表示返回的值擎值,還有就是布爾值done,表示是迭代完成

function buy(books){
  let i = 0;
  return{
    next(){
      let done = i ===books.length;
      let value = !done ? books[i++]:undefined;
      return {
        value:value,
        done:done
      }
    }
  }
}

let iterators = buy(['js','html']);
var curr;
do{
    curr = iterators.next();
  console.log(curr);
}while(!curr.done);

9.3 Generators

生成器用于創(chuàng)建迭代器

function* buy(boos){
    for(var i=0;i<boos.length;i++){
        yield books[i];
  }
}
let buying = buy(['js','html]);
var curr;
do {
    curr = buying.next();
  console.log(curr);
}while(!curr.done);

10. 集合

10.1 Set

一個(gè)Set是一堆東西的集合逐抑,Set 有點(diǎn)像數(shù)組鸠儿,不過(guò)跟數(shù)組不一樣的是,Set里面不能有重復(fù)的內(nèi)容

var books = new Set();
books.add('js');
books.add('js');//添加重復(fù)元素的集合元素個(gè)數(shù)不會(huì)變化
books.add('html');
books.forEach(function(book){ // 循環(huán)集合
    console.log(book);
})
console.log(book.size);//集合中元數(shù)的個(gè)數(shù)
console.log(books.has('js'));//判斷集合是否有此元素
books.delete('js');
console.log(books.size);
console.log(books.has('js'));
books.clear();//清空set
console.log(books.size);

10.2 Map

可以使用Map來(lái)組織這個(gè)名值對(duì)的數(shù)據(jù)

var books = new Map();
books.set('js',{name:'js'});//向map中添加元素
books.set('html',{name:'html'});
console.log(books.size);//查看集合中的元素
console.log(books.get('js'));//通過(guò)key獲取值
books.delete('js');//執(zhí)行key刪除元素
console.log(books.has('js'));//判斷map中有沒(méi)有key
book.forEach((value,key)=>{
    console.log(key+'='+value);
})
books.clear();//清空map

11. 模塊

可以根據(jù)應(yīng)用的需求吧代碼分成不同的模塊厕氨,每個(gè)模塊里可以導(dǎo)出它需要讓其他模塊使用的東西进每,在其他模塊里面可以導(dǎo)入這些模塊,導(dǎo)出的東西命斧。

11.1 模塊

在瀏覽器中使用模塊需要借助 導(dǎo)出

export var name = 'wjh';
export var age = 8;

導(dǎo)入

//import {name,age} from './school.js';
import * as school from './school.js';
console.log(school.name,school.age);

在頁(yè)面中引用

<script src="https://google.github.io/traceur-compiler/bin/traceur.js"></script>
<script src="https://google.github.io/traceur-compiler/bin/BrowserSystem.js"></script>
<script src="https://google.github.io/traceur-compiler/src/bootstrap.js"></script>
<script type="module" src="index.js"></script>

11.2 重命名

導(dǎo)出時(shí)重命名

function say(){
    console.log('say');
}
export {say as say2};

導(dǎo)入時(shí)重命名

import {say2 as say3} from './school.js'

11.3 默認(rèn)導(dǎo)出

每個(gè)模塊都可以有一個(gè)默認(rèn)要導(dǎo)出的東西

export default function say(){
    console.log('say')
}

導(dǎo)入

import say from './school.js'

11.4 深度克隆

var parent = {
  age: 5,
  hobby: [1, 2, 3],
  home: {city: '北京'},
};

var child = extendDeep(parent);
child.age = 6;
child.hobby.push('4');
child.home.city = '廣東';
console.log('child ', child); //[1, 2, 3, 4]
console.log('parent ', parent);
function extend(parent) {
  let child;
  if (Object.prototype.toString.call(parent) == '[object Object]') {
    child = {};
    for (let key in parent) {
      child[key] = extend(parent[key])
    }
  } else if (Object.prototype.toString.call(parent) == '[object Array]') {
    child = parent.map(item => extend(item));
  } else {
    return parent;
  }
  return child;
}

function extendDeep(parent, child) {
  child = child || {};
  for (var key in parent) {
    if (typeof parent[key] === "object") {
      child[key] = (Object.prototype.toString.call(parent[key]) === "[object Array]") ? [] : {};
      extendDeep(parent[key], child[key]);
    } else {
      child[key] = parent[key];
    }
  }
  return child;
}

12.JavaScript(ES6) 中條件語(yǔ)句

12.1 使用 Array.includes 來(lái)處理多個(gè)條件

function test(fruit) {
  if (fruit == 'apple' || fruit == 'strawberry') {
    console.log('red');
  }
}

優(yōu)化變成 ->>

function test(fruit) {
  // 條件提取到數(shù)組中
  const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];
 
  if (redFruits.includes(fruit)) {
    console.log('red');
  }
}

12.2 減少嵌套田晚,提前使用 return 語(yǔ)句

function test(fruit, quantity) {
  const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];
 
  // 條件 1:fruit 必須有值
  if (fruit) {
    // 條件 2:必須為紅色
    if (redFruits.includes(fruit)) {
      console.log('red');
 
      // 條件 3:數(shù)量必須大于 10
      if (quantity > 10) {
        console.log('big quantity');
      }
    }
  } else {
    throw new Error('No fruit!');
  }
}
 
// 測(cè)試結(jié)果
test(null); // 拋出錯(cuò)誤:No fruits
test('apple'); // 打印:red
test('apple', 20); // 打庸帷:red贤徒,big quantity

優(yōu)化

/* 在發(fā)現(xiàn)無(wú)效條件時(shí)提前 return */
 
function test(fruit, quantity) {
  const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];
 
  // 條件 1:提前拋出錯(cuò)誤
  if (!fruit) throw new Error('No fruit!');
 
  // 條件2:必須為紅色
  if (redFruits.includes(fruit)) {
    console.log('red');
 
    // 條件 3:數(shù)量必須大于 10
    if (quantity > 10) {
      console.log('big quantity');
    }
  }
}

為了減少一個(gè)嵌套層級(jí),優(yōu)化編碼風(fēng)格

/* 在發(fā)現(xiàn)無(wú)效條件時(shí)提前 return */
 
function test(fruit, quantity) {
  const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];
 
  if (!fruit) throw new Error('No fruit!'); // 條件 1:提前拋出錯(cuò)誤
  if (!redFruits.includes(fruit)) return;  // 條件 2:當(dāng) fruit 不是紅色的時(shí)候汇四,提前 return
 
  console.log('red');
 
  // 條件 3:必須是大量存在
  if (quantity > 10) {
    console.log('big quantity');
  }
}

12.3.使用函數(shù)的默認(rèn)參數(shù) 和 解構(gòu)

function test(fruit, quantity) {
  if (!fruit) return;
  const q = quantity || 1; // 如果沒(méi)有提供 quantity 參數(shù)接奈,則默認(rèn)為 1
 
  console.log(`We have ${q} ${fruit}!`);
}
 
// 測(cè)試結(jié)果
test('banana'); // We have 1 banana!
test('apple', 2); // We have 2 apple!

但是q在這邊不直觀所有優(yōu)化

function test(fruit, quantity = 1) { // i如果沒(méi)有提供 quantity 參數(shù),則默認(rèn)為 1
  if (!fruit) return;
  console.log(`We have ${quantity} ${fruit}!`);
}
 
// 測(cè)試結(jié)果
test('banana'); // We have 1 banana!
test('apple', 2); // We have 2 apple!

但是這邊 也可能是個(gè)對(duì)象

// 解構(gòu) —— 只獲得 name 屬性
// 參數(shù)默認(rèn)分配空對(duì)象 {}
function test({name} = {}) {
  console.log (name || 'unknown');
}
 
//測(cè)試結(jié)果
test(undefined); // unknown
test({ }); // unknown
test({ name: 'apple', color: 'red' }); // apple

12.4 選擇 Map / Object 字面量通孽,而不是Switch語(yǔ)句

function test(color) {
  // 使用 switch case 語(yǔ)句序宦,根據(jù)顏色找出對(duì)應(yīng)的水果
  switch (color) {
    case 'red':
      return ['apple', 'strawberry'];
    case 'yellow':
      return ['banana', 'pineapple'];
    case 'purple':
      return ['grape', 'plum'];
    default:
      return [];
  }
}
 
//測(cè)試結(jié)果
test(null); // []
test('yellow'); // ['banana', 'pineapple']

這邊建議使用對(duì)象,更加清晰

// 使用對(duì)象字面量背苦,根據(jù)顏色找出對(duì)應(yīng)的水果
  const fruitColor = {
    red: ['apple', 'strawberry'],
    yellow: ['banana', 'pineapple'],
    purple: ['grape', 'plum']
  };
 
function test(color) {
  return fruitColor[color] || [];
}

但是這邊是很有可能為網(wǎng)絡(luò)數(shù)據(jù)互捌,無(wú)法判斷red這樣的變量,那么就用arry.filter 來(lái)過(guò)濾

const fruits = [
    { name: 'apple', color: 'red' }, 
    { name: 'strawberry', color: 'red' }, 
    { name: 'banana', color: 'yellow' }, 
    { name: 'pineapple', color: 'yellow' }, 
    { name: 'grape', color: 'purple' }, 
    { name: 'plum', color: 'purple' }
];
 
function test(color) {
  // 使用 Array filter  行剂,根據(jù)顏色找出對(duì)應(yīng)的水果
 
  return fruits.filter(f => f.color == color);
}

12.5 使用 Array.every 和 Array.some 來(lái)處理全部/部分滿足條件

我們想檢查所有水果是否都是紅色的

const fruits = [
    { name: 'apple', color: 'red' },
    { name: 'banana', color: 'yellow' },
    { name: 'grape', color: 'purple' }
  ];
 
function test() {
  let isAllRed = true;
 
  // 條件:所有的水果都必須是紅色
  for (let f of fruits) {
    if (!isAllRed) break;
    isAllRed = (f.color == 'red');
  }
 
  console.log(isAllRed); // false
}

使用 arry.every來(lái)過(guò)濾

const fruits = [
    { name: 'apple', color: 'red' },
    { name: 'banana', color: 'yellow' },
    { name: 'grape', color: 'purple' }
  ];
 
function test() {
  // 條件:簡(jiǎn)短方式秕噪,所有的水果都必須是紅色
  const isAllRed = fruits.every(f => f.color == 'red');
 
  console.log(isAllRed); // false
}

如果我們想要檢查是否有至少一個(gè)水果是紅色的,我們可以使用 Array.some 僅用一行代碼就實(shí)現(xiàn)出來(lái)

const fruits = [
    { name: 'apple', color: 'red' },
    { name: 'banana', color: 'yellow' },
    { name: 'grape', color: 'purple' }
];
 
function test() {
  // 條件:是否存在紅色的水果
  const isAnyRed = fruits.some(f => f.color == 'red');
 
  console.log(isAnyRed); // true
}

13 promise

13.1 異步回調(diào)

13.1.1 回調(diào)地獄

在需要多個(gè)操作的時(shí)間厚宰,會(huì)導(dǎo)致多個(gè)回調(diào)函數(shù)嵌套腌巾,導(dǎo)致代碼不夠直觀,就常說(shuō)的回調(diào)地獄

13.1.2 并行結(jié)果

如果幾個(gè)異步操作之間并沒(méi)有前后順序之分固阁,但需要等多個(gè)異步完成操作完成后才能執(zhí)行后續(xù)的任務(wù)壤躲,無(wú)法實(shí)現(xiàn)并行節(jié)約時(shí)間

13.2 Promise

promise本意是承諾,在程序中的意思就是承諾我過(guò)一段時(shí)間后會(huì)給你一個(gè)結(jié)果备燃。什么時(shí)間會(huì)用到過(guò)一段時(shí)間碉克?答案是異步操作,異步是指可能比較長(zhǎng)時(shí)間才有結(jié)果的才做并齐,例如網(wǎng)絡(luò)請(qǐng)求漏麦、讀取本地文件等

13.3 Promise的三種狀態(tài)

  • Pending Promise對(duì)象勢(shì)力創(chuàng)建時(shí)候的初始化狀態(tài)
  • Fulfilled 可以理解為成功的狀態(tài)
  • Rejected 可以理解為失敗的狀態(tài)

then方法就是用來(lái)指定Promise 對(duì)象的狀態(tài)改變時(shí)確定執(zhí)行的操作客税,resolve時(shí)執(zhí)行第一個(gè)函數(shù)(onFulfilled),reject時(shí)執(zhí)行第二函數(shù)(onRejected)

13.4 構(gòu)造一個(gè)Promise

13.4.1 使用Promise

let promise = new Promise((resolve,reject)=>{
        setTimeout(()=>{
        if(Math.random()>0.5)
        resolve('This is resolve!')
      else
        reject('This is reject')
    },1000);
});
promise.then(Fulfilled,Rejected)
  • 構(gòu)造一個(gè)Promise實(shí)例需要給Promise構(gòu)造函數(shù)傳入一個(gè)函數(shù)
  • 傳入的函數(shù)需要有兩個(gè)形參,兩個(gè)形參都是function類型的參數(shù)撕贞。
    • 第一個(gè)形參運(yùn)行后會(huì)讓Promise實(shí)例處于resolve狀態(tài)更耻,所以我們一般給第一個(gè)形參命名為resolve,使 Promise對(duì)象的狀態(tài)改變成成功捏膨,同時(shí)傳遞一個(gè)參數(shù)用于后續(xù)成功后的操作
    • 第一個(gè)形參運(yùn)行后悔讓Promise實(shí)例處于reject狀態(tài)秧均,所以我們一般給第一個(gè)形參命名為reject,將Promise對(duì)象的狀態(tài)改變?yōu)槭『叛模聦㈠e(cuò)誤的信息傳遞到后續(xù)錯(cuò)誤處理的操作

13.4.2 es5模擬Promise

function Promise(fn){
    this.success(data);
},(error)=>{
    this.error();
}

Promise.prtotype.resolve = function (data){
    this.success(data);
}

Promise.prototype.then = function (success,error){
    this.success = success;
    this.error = error;
}

13.4.3 es5模擬Promise

class Promise{
    constructor(fn){
        fn((data)=>{
        this.success(data);
      },(error)=>{
        this.error();
      })
  }
  
  resolve(data){
    this.success(data);
  }
  
  reject(error){
    this.error(error);
  }
  
  then(success,error){
    this.success = success;
    this.error = error;
    console.log(this);
  }

}

13.5 promise 做為函數(shù)的返回值

function ajaxPromise(queryUrl){
    return new Promise((resolve,reject)=>{
    xhr.open('GET',queryUrl,ture);
    xhr.send(null);
    xhr.onreadystatechange = () =>{
            if(xhr.readyState === 4 ){
            if(xhr.status === 200){
            resolve(xhr.responseText);
          }else{
            reject(xhr.responseText);
          }
        }
    }
  })
}


ajaxPromise('http://www.baidu.com')
    .then((value)=>{
    console.log(value);
  })
  .catch((err)=>{
    console.error(err);
 });

13.6 promise的鏈?zhǔn)秸{(diào)用

  • 每次調(diào)用返回的都是一個(gè)新的Promise實(shí)例
  • 鏈?zhǔn)秸{(diào)用的參數(shù)通過(guò)返回值傳遞

then 可以使用鏈?zhǔn)秸{(diào)用的寫法原因在于目胡,每一次執(zhí)行該方法時(shí)總是會(huì)返回一個(gè) Promise 對(duì)象

readFile('1.txt').then(function(data){
    console.log(data);
}).then(function (data){
    console.log(data);
  return readFile(data);
}).then(function (data){
    console.log(data);
}).catch(function (err){
    console.log(err);
})

13.7 promise API

13.7.1 Promise.all

  • 參數(shù):接受一個(gè)數(shù)組,數(shù)組內(nèi)都是Promise實(shí)例
  • 返回值: 返回一個(gè) promise 實(shí)例链快,這個(gè)promise 實(shí)例的狀態(tài)轉(zhuǎn)移取決于參數(shù)的 promise實(shí)例的狀態(tài)變化誉己。當(dāng)參數(shù)處于resolve狀態(tài)時(shí),返回resolve狀態(tài)。如果參數(shù)中任意一個(gè)實(shí)例處于reject狀態(tài),返回的promise實(shí)例變?yōu)閞eject狀態(tài)浓领。
Promise.all([p1,p2]).then(function(result){
    console.log(result); //[ '2.txt', '2' ]
})

不管兩個(gè)promise誰(shuí)先完成,Promise.all 方法會(huì)按照數(shù)組里面的順序?qū)⒔Y(jié)果返回

13.7.2 Promise.race

  • 參數(shù):接受一個(gè)數(shù)組蚣旱,數(shù)組內(nèi)都是Promise實(shí)例
  • 返回值: 返回一個(gè) promise 實(shí)例,這個(gè)promise 實(shí)例的狀態(tài)轉(zhuǎn)移取決于參數(shù)的 promise實(shí)例的狀態(tài)變化。當(dāng)參數(shù)處于resolve狀態(tài)時(shí),返回resolve狀態(tài)疼阔。如果參數(shù)中任意一個(gè)實(shí)例處于reject狀態(tài),返回的promise實(shí)例變?yōu)閞eject狀態(tài)半夷。
Promise.race([p1,p2]).then(function(result){
    console.log(result); //[ '2.txt', '2' ]
})

13.7.3 Promise.resolve

返回一個(gè)Promise 實(shí)例,這個(gè)實(shí)例處于resolve狀態(tài)迅细。<br />根據(jù)傳入的參數(shù)不同有不同的功能:

  • 值(對(duì)象巫橄、數(shù)組、字符串等):作為resolve傳遞出去的值
  • Promise 實(shí)例 : 原封不動(dòng)返回

Promise.reject

返回一個(gè)Promise實(shí)例茵典,這個(gè)實(shí)例處于reject狀態(tài)

  • 參數(shù)一般就是拋出的錯(cuò)誤信息湘换。

13.8 q

Q是一個(gè)在Javascrip中實(shí)現(xiàn)promise的模塊

13.8.1 q的基本用法

var Q = require('q');
var fs = require('fs');
function read(filename){
    var deferred = Q.defer();
  fs.readFile(filename,'utf8',function)(err,data){
    if(err){
        deferred.reject(err);
    }else{
        deferred.resolve(data);
    }
  });
}

read('1.txt1').then(function(data){
    console.log(data);
},funtcion(error){
    console.error(error);                    
})

13.8.2 q的簡(jiǎn)單實(shí)現(xiàn)

module.exports = {
    defer(){
        var _success,_error;
        return {
            resolve(data){
                _success(data);
            },
            reject(err){
                _error(err);
            },
            promise:{
                then(success,error){
                    _success = success;
                    _error = error;
                }
            }
        }
    }
}

13.8.3 q的實(shí)現(xiàn)

var defer = function () {
    var pending = [], value;
    return {
        resolve: function (_value) {
            if (pending) {
                value = _value;
                for (var i = 0, ii = pending.length; i < ii; i++) {
                    var callback = pending[i];
                    callback(value);
                }
                pending = undefined;
            }
        },
        promise: {
            then: function (callback) {
                if (pending) {
                    pending.push(callback);
                } else {
                    callback(value);
                }
            }
        }
    };
};

13.9 bluebird

實(shí)現(xiàn) promise 標(biāo)準(zhǔn)的庫(kù)是功能最全,速度最快的一個(gè)庫(kù)

13.9.1 bluebird經(jīng)典使用

var Promise = require('./bluebird');

var readFile = Promise.promisify(require("fs").readFile);
readFile("1.txt", "utf8").then(function(contents) {
    console.log(contents);
})

var fs = Promise.promisifyAll(require("fs"));

fs.readFileAsync("1.txt", "utf8").then(function (contents) {
    console.log(contents);
})

13.9.2 bluebird簡(jiǎn)單實(shí)現(xiàn)

module.exports = {
    promisify(fn){
        return function () {
            var args = Array.from(arguments);
            return new Promise(function (resolve, reject) {
                fn.apply(null, args.concat(function (err) {
                    if (err) {
                        reject(err);
                    } else {
                        resolve(arguments[1])
                    }
                }));
            })
        }
    },
    promisifyAll(obj){
        for(var attr in obj){
            if(obj.hasOwnProperty(attr) && typeof obj[attr] =='function'){
                obj[attr+'Async'] = this.promisify(obj[attr]);
            }
        }
        return obj;
    }
}

13.10 動(dòng)畫

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>move</title>
    <style>
        .square{
            width:40px;
            height:40px;
            border-radius: 50%;
        }
        .square1{
            background-color: red;
        }
        .square2{
            background-color: yellow;
        }
        .square3{
            background-color: blue;
        }
    </style>
</head>
<body>
<div class="square square1" style="margin-left: 0"></div>
<div class="square square2" style="margin-left: 0"></div>
<div class="square square3" style="margin-left: 0"></div>
</body>
<script>
  var square1 = document.querySelector('.square1');
  var square2 = document.querySelector('.square2');
  var square3 = document.querySelector('.square3');

  /*function move(element,target,resolve){
    let timer = setInterval(function(){
      var marginLeft = parseInt(element.style.marginLeft, 10);
      if(marginLeft == target){
        resolve();
      }else{
        element.style.marginLeft = ++marginLeft+'px';
      }
    },13);
  }*/
  function move(element,target,resolve){
    let current = 0;
    let timer = setInterval(function(){
      element.style.transform=`translateX(${++current}px)`;
      if(current>target){
        clearInterval(timer);
        resolve();
      };
    },13);
  }
  function animate(element,target){
    return new Promise(function(resolve,reject){
      move(element,target,resolve);
    });
  }
  animate(square1,100)
    .then(function(){
      return animate(square2,100);
    })
    .then(function(){
      return animate(square3,100);
    });
</script>
</html>

13.11. co

13.11.1 co初體驗(yàn)

let fs = require('fs');
function getNumber(){
  return new Promise(function (resolve,reject) {
    setTimeout(function(){
      let number = Math.random();
      if(number >.5){
        resolve(number);
      }else{
        reject('數(shù)字太小');
      }
    },1000);
  });
}
function *read(){
  let a = yield getNumber();
  console.log(a);
  let b = yield 'b';
  console.log(b);
  let c = yield getNumber();
  console.log(c);
}

function co(gen){
  return new Promise(function(resolve,reject){
    let g = gen();
    function next(lastValue){
      let {done,value} = g.next(lastValue);
      if(done){
         resolve(lastValue);
      }else{
        if(value instanceof Promise){
          value.then(next,function(val){
            reject(val);
          });
        }else{
          next(value);
        }
      }
    }
    next();
  });
}
co(read).then(function(data){
  console.log(data);
},function(reason){
  console.log(reason);
});

13.11.2 co連續(xù)讀文件

let fs = require('fs');
function readFile(filename){
  return new Promise(function (resolve,reject) {
    fs.readFile(filename,'utf8',function(err,data){
      if(err)
        reject(err);
      else
        resolve(data);
    })
  });
}
function *read(){
  let a = yield readFile('./1.txt');
  console.log(a);
  let b = yield readFile('./2.txt');
  console.log(b);
}

function co(gen){
  let g = gen();
  function next(val){
    let {done,value} = g.next(val);
    if(!done){
      value.then(next);
    }
  }
  next();
}

13.12 Promise/A+完整實(shí)現(xiàn)

function Promise(executor) {
  let self = this;
  self.status = "pending";
  self.value = undefined;
  self.onResolvedCallbacks = [];
  self.onRejectedCallbacks = [];
  function resolve(value) {
    if (value instanceof Promise) {
      return value.then(resolve, reject)
    }
    setTimeout(function () { // 異步執(zhí)行所有的回調(diào)函數(shù)
      if (self.status == 'pending') {
        self.value = value;
        self.status = 'resolved';
        self.onResolvedCallbacks.forEach(item => item(value));
      }
    });

  }

  function reject(value) {
    setTimeout(function () {
      if (self.status == 'pending') {
        self.value = value;
        self.status = 'rejected';
        self.onRejectedCallbacks.forEach(item => item(value));
      }
    });
  }

  try {
    executor(resolve, reject);
  } catch (e) {
    reject(e);
  }
}
function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    return reject(new TypeError('循環(huán)引用'));
  }
  let then, called;

  if (x != null && ((typeof x == 'object' || typeof x == 'function'))) {
    try {
      then = x.then;
      if (typeof then == 'function') {
        then.call(x, function (y) {
          if (called)return;
          called = true;
          resolvePromise(promise2, y, resolve, reject);
        }, function (r) {
          if (called)return;
          called = true;
          reject(r);
        });
      } else {
        resolve(x);
      }
    } catch (e) {
      if (called)return;
      called = true;
      reject(e);
    }
  } else {
    resolve(x);
  }
}
Promise.prototype.then = function (onFulfilled, onRejected) {
  let self = this;
  onFulfilled = typeof onFulfilled == 'function' ? onFulfilled : function (value) {
    return value
  };
  onRejected = typeof onRejected == 'function' ? onRejected : function (value) {
    throw value
  };
  let promise2;
  if (self.status == 'resolved') {
    promise2 = new Promise(function (resolve, reject) {
      setTimeout(function () {
        try {
          let x = onFulfilled(self.value);
          resolvePromise(promise2, x, resolve, reject);
        } catch (e) {
          reject(e);
        }
      });

    });
  }
  if (self.status == 'rejected') {
    promise2 = new Promise(function (resolve, reject) {
      setTimeout(function () {
        try {
          let x = onRejected(self.value);
          resolvePromise(promise2, x, resolve, reject);
        } catch (e) {
          reject(e);
        }
      });
    });
  }
  if (self.status == 'pending') {
    promise2 = new Promise(function (resolve, reject) {
      self.onResolvedCallbacks.push(function (value) {
        try {
          let x = onFulfilled(value);
          resolvePromise(promise2, x, resolve, reject);
        } catch (e) {
          reject(e);
        }
      });
      self.onRejectedCallbacks.push(function (value) {
        try {
          let x = onRejected(value);
          resolvePromise(promise2, x, resolve, reject);
        } catch (e) {
          reject(e);
        }
      });
    });
  }
  return promise2;
}
Promise.prototype.catch = function (onRejected) {
  return this.then(null, onRejected);
}
Promise.all = function (promises) {
  return new Promise(function (resolve, reject) {
    let result = [];
    let count = 0;
    for (let i = 0; i < promises.length; i++) {
      promises[i].then(function (data) {
        result[i] = data;
        if (++count == promises.length) {
          resolve(result);
        }
      }, function (err) {
        reject(err);
      });
    }
  });
}

Promise.deferred = Promise.defer = function () {
  var defer = {};
  defer.promise = new Promise(function (resolve, reject) {
    defer.resolve = resolve;
    defer.reject = reject;
  })
  return defer;
}
/**
 * npm i -g promises-aplus-tests
 * promises-aplus-tests Promise.js
 */
try {
  module.exports = Promise
} catch (e) {
}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末统阿,一起剝皮案震驚了整個(gè)濱河市彩倚,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌扶平,老刑警劉巖帆离,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異结澄,居然都是意外死亡哥谷,警方通過(guò)查閱死者的電腦和手機(jī)岸夯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)们妥,“玉大人猜扮,你說(shuō)我怎么就攤上這事〖嗌簦” “怎么了旅赢?”我有些...
    開(kāi)封第一講書人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)惑惶。 經(jīng)常有香客問(wèn)我鲜漩,道長(zhǎng),這世上最難降的妖魔是什么集惋? 我笑而不...
    開(kāi)封第一講書人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任孕似,我火速辦了婚禮,結(jié)果婚禮上刮刑,老公的妹妹穿的比我還像新娘喉祭。我一直安慰自己,他們只是感情好雷绢,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布泛烙。 她就那樣靜靜地躺著,像睡著了一般翘紊。 火紅的嫁衣襯著肌膚如雪蔽氨。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 51,688評(píng)論 1 305
  • 那天帆疟,我揣著相機(jī)與錄音鹉究,去河邊找鬼。 笑死踪宠,一個(gè)胖子當(dāng)著我的面吹牛自赔,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播柳琢,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼绍妨,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了柬脸?” 一聲冷哼從身側(cè)響起他去,我...
    開(kāi)封第一講書人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎倒堕,沒(méi)想到半個(gè)月后灾测,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡涩馆,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年行施,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了允坚。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蛾号,死狀恐怖稠项,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情鲜结,我是刑警寧澤展运,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站精刷,受9級(jí)特大地震影響拗胜,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜怒允,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一埂软、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧纫事,春花似錦勘畔、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至钾唬,卻和暖如春万哪,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背抡秆。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工奕巍, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人琅轧。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓伍绳,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親乍桂。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容