前端新特性分享

1.類字段聲明

在 ES13 之前齐帚,類字段只能在構(gòu)造函數(shù)中聲明。與許多其他語(yǔ)言不同彼哼,我們不能在類的最外層范圍內(nèi)聲明或定義它們对妄。

class Car {  
  constructor() {    
    this.color = 'blue';    
    this.age = 2;  
  }
}
const car = new Car();
console.log(car.color); // blue
console.log(car.age); // 2

ES13 消除了這個(gè)限制。現(xiàn)在我們可以編寫如下代碼:

class Car {  
  color = 'yellow';  
  age = 2;
}
const car = new Car();
console.log(car.color); // yellow
console.log(car.age); // 2

2.私有方法和字段

以前敢朱,不能在類中聲明私有成員剪菱。成員通常以下劃線 (_) 為前綴,表示它是私有的拴签,但仍然可以從類外部訪問和修改孝常。

class Person {  
  _firstName = 'Joseph'; 
   _lastName = 'Stevens';  
  get name() {    
    return `${this._firstName} ${this._lastName}`;  
  }
}
const person = new Person();
console.log(person.name); // Joseph Stevens
// Members intended to be private can still be accessed
// from outside the class
console.log(person._firstName); // Joseph
console.log(person._lastName); // Stevens
// They can also be modified
person._firstName = 'Robert';
person._lastName = 'Becker';
console.log(person.name); // Robert Becker

使用 ES13,我們現(xiàn)在可以將私有字段和成員添加到類中蚓哩,方法是在其前面加上井號(hào) (#)构灸。試圖從類外部訪問它們會(huì)導(dǎo)致錯(cuò)誤:

class Person {  
  #firstName = 'Joseph';  
  #lastName = 'Stevens';  
  get name() {    
    return `${this.#firstName} ${this.#lastName}`;  
  }
}
const person = new Person();
console.log(person.name); // Joseph Stevens
// SyntaxError: Private field '#firstName' must be declared //in an enclosing class
console.log(person.#firstName);
console.log(person.#lastName);

請(qǐng)注意,這里拋出的錯(cuò)誤是語(yǔ)法錯(cuò)誤岸梨,發(fā)生在編譯時(shí)冻押,因此沒有部分代碼運(yùn)行。編譯器甚至不希望您嘗試從類外部訪問私有字段盛嘿,因此它假定您正在嘗試聲明一個(gè)。

3.頂層等待操作符

在 JavaScript 中括袒,await 運(yùn)算符用于暫停執(zhí)行次兆,直到 Promise 被解決(履行或拒絕)。
以前锹锰,我們只能在 async 函數(shù)中使用此運(yùn)算符 - 使用 async 關(guān)鍵字聲明的函數(shù)芥炭。我們無法在全局范圍內(nèi)這樣做。

function setTimeoutAsync(timeout) {  
  return new Promise((resolve) => {    
    setTimeout(() => {      
      resolve();    
    }, timeout);  
  });
}// SyntaxError: await is only valid in async functions
await setTimeoutAsync(3000);

使用 ES13恃慧,現(xiàn)在我們可以:

function setTimeoutAsync(timeout) {  
  return new Promise((resolve) => {    
    setTimeout(() => {   
      console.log(111)   
      resolve();    
    }, timeout);  
  });
}
// Waits for timeout - no error thrown
await setTimeoutAsync(3000);

好處:
1.代碼更簡(jiǎn)練园蝠,不用多寫一層function。
2.在父級(jí)調(diào)用該子模塊時(shí)痢士,會(huì)根據(jù)await執(zhí)行同步命令彪薛,暫停父級(jí)執(zhí)行。

4.靜態(tài)類字段和靜態(tài)私有方法

我們現(xiàn)在可以在 ES13 中為類聲明靜態(tài)字段和靜態(tài)私有方法。靜態(tài)方法可以使用 this 關(guān)鍵字訪問類中的其他私有/公共靜態(tài)成員善延,實(shí)例方法可以使用 this.constructor 訪問它們少态。

class Person {    
  static #count = 0;  
  static getCount() {    
    return this.#count; 
  }  
  constructor() {    
    this.constructor.#incrementCount();  
  }  
  static #incrementCount() {    
    this.#count++;  
  }
}
const person1 = new Person();
const person2 = new Person();
console.log(Person.getCount()); // 2

5.類靜態(tài)塊

ES13 允許在創(chuàng)建類時(shí)定義只執(zhí)行一次的靜態(tài)塊。這類似于其他支持面向?qū)ο缶幊痰恼Z(yǔ)言(如 C# 和 Java)中的靜態(tài)構(gòu)造函數(shù)易遣。
一個(gè)類的類主體中可以有任意數(shù)量的靜態(tài) {} 初始化塊彼妻。它們將與任何交錯(cuò)的靜態(tài)字段初始值設(shè)定項(xiàng)一起按照聲明的順序執(zhí)行。我們可以在靜態(tài)塊中使用超屬性來訪問超類的屬性豆茫。

class Vehicle {  
  static defaultColor = 'blue';
}
class Car extends Vehicle {  
  static colors = [];  
  static {    
    this.colors.push(super.defaultColor, 'red');  
  }  
  static {    
    this.colors.push('green');  
  }
}
console.log(Car.colors); // [ 'blue', 'red', 'green' ]

6. 私有字段檢查

我們可以使用這個(gè)新特性來檢查
一個(gè)對(duì)象中是否有一個(gè)特定的私有字段侨歉,使用 in 運(yùn)算符。

class Car { 
  #color;  
  hasColor() {    
    return #color in this;  
  }
}
const car = new Car();
console.log(car.hasColor()); // true;
class Car {  
  #color;  
  hasColor() {    
    return #color in this;  
  }
}
class House {  
  #color;  
  hasColor() {    
    return #color in this;  
  }
}
const car = new Car();
const house = new House();
console.log(car.hasColor()); // true;
console.log(car.hasColor.call(house)); // false
console.log(house.hasColor()); // true
console.log(house.hasColor.call(car)); // false

7. at() 方法進(jìn)行索引

我們通常在 JavaScript 中使用方括號(hào) ([]) 來訪問數(shù)組的第 N 個(gè)元素揩魂,這通常是一個(gè)簡(jiǎn)單的過程幽邓。我們只訪問數(shù)組的 N - 1 屬性。

const arr = ['a', 'b', 'c', 'd'];
console.log(arr[1]); // b

但是肤京,如果我們想使用方括號(hào)訪問數(shù)組末尾的第 N 個(gè)項(xiàng)目颊艳,我們必須使用 arr.length - N 的索引。

const arr = ['a', 'b', 'c', 'd'];
// 1st element from the end
console.log(arr[arr.length - 1]); // d
// 2nd element from the end
console.log(arr[arr.length - 2]); // c

新的 at() 方法讓我們可以更簡(jiǎn)潔忘分、更有表現(xiàn)力地做到這一點(diǎn)棋枕。要訪問數(shù)組末尾的第 N 個(gè)元素,我們只需將負(fù)值 -N 傳遞給 at()妒峦。

const arr = ['a', 'b', 'c', 'd'];
// 1st element from the end
console.log(arr.at(-1)); // d
// 2nd element from the end
console.log(arr.at(-2)); // c

除了數(shù)組重斑,字符串和 TypedArray 對(duì)象現(xiàn)在也有 at() 方法。

const str = 'Coding Beauty';
console.log(str.at(-1)); // y
console.log(str.at(-2)); // t

const typedArray = new Uint8Array([16, 32, 48, 64]);
console.log(typedArray.at(-1)); // 64
console.log(typedArray.at(-2)); // 48

8.RegExp 匹配索引

這個(gè)新功能允許我們指定我們想要獲取給定字符串中 RegExp 對(duì)象匹配的開始和結(jié)束索引肯骇。
以前窥浪,我們只能在字符串中獲取正則表達(dá)式匹配的起始索引。

const str = 'sun and moon';
const regex = /and/;
const matchObj = regex.exec(str);
// [ 'and', index: 4, input: 'sun and moon', groups: undefined ]
console.log(matchObj);

我們現(xiàn)在可以指定一個(gè)d正則表達(dá)式標(biāo)志來獲取匹配開始和結(jié)束的兩個(gè)索引笛丙。
設(shè)置 d 標(biāo)志后漾脂,返回的對(duì)象將具有包含開始和結(jié)束索引的 indices 屬性。

const str = 'sun and moon';
const regex = /and/d;
const matchObj = regex.exec(str);
//[  'and',  index: 4,  input: 'sun and moon',  groups: undefined,  indices: [ [ 4, 7 ], groups: undefined ]] 
console.log(matchObj);

9. Object.hasOwn() 方法

在 JavaScript 中胚鸯,我們可以使用Object.prototype.hasOwnProperty() 方法來檢查對(duì)象是否具有給定的屬性骨稿。

class Car {  
  color = 'green';  
  age = 2;
}
const car = new Car();
console.log(car.hasOwnProperty('age')); // true
console.log(car.hasOwnProperty('name')); // false

但是這種方法存在一定的問題。一方面姜钳,
Object.prototype.hasOwnProperty() 方法不受保護(hù) - 它可以通過為類定義自定義hasOwnProperty() 方法來覆蓋坦冠,該方法可能具有Object.prototype.hasOwnProperty() 完全不同的行為。

class Car {  
  color = 'green';  
  age = 2;  
  hasOwnProperty() {    
    return false;  
  }
}
const car = new Car();
console.log(car.hasOwnProperty('age')); // false
console.log(car.hasOwnProperty('name')); // false

另一個(gè)問題是哥桥,對(duì)于使用 null 原型創(chuàng)建的對(duì)象(使用 Object.create(null))辙浑,嘗試對(duì)其調(diào)用此方法會(huì)導(dǎo)致錯(cuò)誤。

const obj = Object.create(null);
obj.color = 'green';
obj.age = 2;
// TypeError: obj.hasOwnProperty is not a function
console.log(obj.hasOwnProperty('color'));

解決這些問題的一種方法是使用調(diào)用Object.prototype.hasOwnProperty Function 屬性上的 call() 方法拟糕,如下所示:

const obj = Object.create(null);
obj.color = 'green';
obj.age = 2;
obj.hasOwnProperty = () =>false;
console.log(Object.prototype.hasOwnProperty.call(obj, 'color')); // true
console.log(Object.prototype.hasOwnProperty.call(obj, 'name')); // false

這不是很方便判呕。我們可以編寫一個(gè)可重用的函數(shù)來避免重復(fù):

function objHasOwnProp(obj, propertyKey) {  
  return Object.prototype.hasOwnProperty.call(obj, propertyKey);
}
const obj = Object.create(null);
obj.color = 'green';
obj.age = 2;
obj.hasOwnProperty = () => false;
console.log(objHasOwnProp(obj, 'color')); // true
console.log(objHasOwnProp(obj, 'name')); // false

不過沒有必要倦踢,因?yàn)槲覀兛梢允褂眯碌膬?nèi)置 Object.hasOwn() 方法。與我們的可重用函數(shù)一樣佛玄,它接受對(duì)象和屬性作為參數(shù)硼一,如果指定的屬性是對(duì)象的直接屬性,則返回 true梦抢。否則般贼,它返回 false。

const obj = Object.create(null);
obj.color = 'green';
obj.age = 2;
obj.hasOwnProperty = () => false;
console.log(Object.hasOwn(obj, 'color')); // true
console.log(Object.hasOwn(obj, 'name')); // false

10. 錯(cuò)誤原因

錯(cuò)誤對(duì)象現(xiàn)在有一個(gè) cause 屬性奥吩,用于指定導(dǎo)致即將拋出的錯(cuò)誤的原始錯(cuò)誤哼蛆。這有助于為錯(cuò)誤添加額外的上下文信息并幫助診斷意外行為。我們可以通過在作為第二個(gè)參數(shù)傳遞給 Error() 構(gòu)造函數(shù)的對(duì)象上設(shè)置 cause 屬性來指定錯(cuò)誤的原因霞赫。

function userAction() {  
  try {    
    apiCallThatCanThrow();  
  } 
  catch (err) {    
    throw new Error('New error message', { cause: err });  
  }
}
try {  
  userAction();
} catch (err) {  
  console.log(err);  
  console.log(`Cause by: ${err.cause}`);
}

11.從最后一個(gè)數(shù)組查找

在 JavaScript 中腮介,我們已經(jīng)可以使用 Array find() 方法在數(shù)組中查找通過指定測(cè)試條件的元素。同樣端衰,我們可以使用 findIndex() 來查找此類元素的索引叠洗。雖然 find() 和 findIndex() 都從數(shù)組的第一個(gè)元素開始搜索,但在某些情況下旅东,最好從最后一個(gè)元素開始搜索灭抑。
在某些情況下,我們知道從最后一個(gè)元素中查找可能會(huì)獲得更好的性能抵代。例如腾节,這里我們?cè)噲D在數(shù)組中獲取值 等于 y 的項(xiàng)目。使用 find() 和 findIndex():

const letters = [  { value: 'v' },  { value: 'w' },  { value: 'x' }, 
 { value: 'y' },  { value: 'z' },];
const found = letters.find((item) => item.value === 'y');
const foundIndex = letters.findIndex((item) => item.value === 'y');
console.log(found); // { value: 'y' }
console.log(foundIndex); // 3

這行得通荤牍,但是由于目標(biāo)對(duì)象更靠近數(shù)組的尾部案腺,如果我們使用 findLast() 和 findLastIndex() 方法從末尾搜索數(shù)組,我們可以讓這個(gè)程序運(yùn)行得更快康吵。

const letters = [  { value: 'v' },  { value: 'w' },  { value: 'x' },  
{ value: 'y' },  { value: 'z' },];
const found = letters.findLast((item) => item.value === 'y');
const foundIndex = letters.findLastIndex((item) => item.value === 'y');
console.log(found); // { value: 'y' }
console.log(foundIndex); // 3

另一個(gè)用例可能需要我們專門從末尾搜索數(shù)組以獲取正確的項(xiàng)目劈榨。例如,如果我們想在數(shù)字列表中找到最后一個(gè)偶數(shù)晦嵌, find() 和 findIndex() 會(huì)產(chǎn)生錯(cuò)誤的結(jié)果:

const nums = [7, 14, 3, 8, 10, 9];
// gives 14, instead of 10
const lastEven = nums.find((value) => value % 2 === 0);
// gives 1, instead of 4
const lastEvenIndex = nums.findIndex((value) => value % 2 === 0);
console.log(lastEven); // 14
console.log(lastEvenIndex); // 1

我們可以在調(diào)用 find() 和 findIndex() 之前調(diào)用數(shù)組的 reverse() 方法來反轉(zhuǎn)元素的順序鞋既。但是這種方法會(huì)導(dǎo)致數(shù)組不必要的突變,因?yàn)?reverse() 將數(shù)組的元素反轉(zhuǎn)到位耍铜。避免這種突變的唯一方法是制作整個(gè)數(shù)組的新副本,這可能會(huì)導(dǎo)致大型數(shù)組出現(xiàn)性能問題跌前。
此外棕兼, findIndex() 仍然無法在反轉(zhuǎn)數(shù)組上工作,因?yàn)榉崔D(zhuǎn)元素也意味著更改它們?cè)谠紨?shù)組中的索引抵乓。要獲得原始索引伴挚,我們需要執(zhí)行額外的計(jì)算靶衍,這意味著編寫更多代碼。

const nums = [7, 14, 3, 8, 10, 9];
const lastEven = nums.findLast((num) => num % 2 === 0);
const lastEvenIndex = nums.findLastIndex((num) => num % 2 === 0);
console.log(lastEven); // 10
console.log(lastEvenIndex); // 4

12.導(dǎo)入斷言

使用這種方式導(dǎo)入茎芋,我們就不需要手動(dòng)解析它了颅眶。
在 import…from… 后面加 assert { type: ‘json’ }

import json from './foo.json' assert { type: 'json' };
console.log(json.answer); // 42

1. String.replaceAll()

replaceAll()方法會(huì)返回一個(gè)全新的字符串,所有符合匹配規(guī)則的字符都將被替換掉田弥,替換規(guī)則可以是字符串或者正則表達(dá)式涛酗。
原始字符串保持不變。

let string = 'hello world, hello ES12'
string.replace(/hello/g,'hi')    // hi world, hi ES12
string.replaceAll('hello','hi')  // hi world, hi ES12

注意的是偷厦,replaceAll 在使用正則表達(dá)式的時(shí)候商叹,如果非全局匹配(/g),會(huì)拋出異常:

let string = 'hello world, hello ES12'
string.replaceAll(/hello/,'hi') 
// Uncaught TypeError: String.prototype.replaceAll called with a non-global

2. 數(shù)字分隔符

數(shù)字分隔符可以在數(shù)字之間創(chuàng)建可視化分隔符只泼,通過 _下劃線來分割數(shù)字剖笙,使數(shù)字更具可讀性:

let budget = 1_000_000_000_000;
budget === 10 ** 12 // true

這個(gè)數(shù)值分隔符沒有指定間隔的位數(shù),也就是說请唱,可以每三位添加一個(gè)分隔符弥咪,也可以每一位、每?jī)晌皇蟆⒚克奈惶砑右粋€(gè)聚至。

123_00 === 12_300 // true
12345_00 === 123_4500 // true

小數(shù)和科學(xué)計(jì)數(shù)法也可以使用數(shù)值分隔符。

0.000_001 // 小數(shù)
1e10_000 // 科學(xué)計(jì)數(shù)法

數(shù)值分隔符有幾個(gè)使用注意點(diǎn)孽惰。

  • 不能放在數(shù)值的最前面(leading)或最后面(trailing)晚岭。
  • 不能兩個(gè)或兩個(gè)以上的分隔符連在一起。
  • 小數(shù)點(diǎn)的前后不能有分隔符勋功。
  • 科學(xué)計(jì)數(shù)法里面坦报,表示指數(shù)的e或E前后不能有分隔符
    下面的寫法都會(huì)報(bào)錯(cuò)。
3_.141
3._141
1_e12
1e_12
123__456
_1464301
1464301_

3.Promise.any

方法接受一組 Promise 實(shí)例作為參數(shù)狂鞋,包裝成一個(gè)新的 Promise 實(shí)例返回片择。

const promise1 = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("promise1");
      //  reject("error promise1 ");
    }, 3000);
  });
};
const promise2 = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("promise2");
      // reject("error promise2 ");
    }, 1000);
  });
};
const promise3 = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("promise3");
      // reject("error promise3 ");
    }, 2000);
  });
};
Promise.any([promise1(), promise2(), promise3()])
  .then((first) => {
    // 只要有一個(gè)請(qǐng)求成功 就會(huì)返回第一個(gè)請(qǐng)求成功的
    console.log(first); // 會(huì)返回promise2
  })
  .catch((error) => {
    // 所有三個(gè)全部請(qǐng)求失敗 才會(huì)來到這里
    console.log("error", error);// err:AggregateError: All promises were rejected
    console.log(error.message)// All promises were rejected
    console.log(error.name) // AggregateError
    console.log(err.errors) // ["error promise1", "error promise2", "error promise3"]
  });

只要參數(shù)實(shí)例有一個(gè)變成fulfilled狀態(tài),包裝實(shí)例就會(huì)變成fulfilled狀態(tài)骚揍;如果所有參數(shù)實(shí)例都變成rejected狀態(tài)字管,包裝實(shí)例就會(huì)變成rejected狀態(tài)。
即:只要其中的一個(gè) promise 成功信不,就返回那個(gè)已經(jīng)成功的 promise 如果可迭代對(duì)象中沒有一個(gè) promise 成功(即所有的 promises 都失敗/拒絕)嘲叔,就返回一個(gè)失敗的 promise 和 AggregateError 類型的實(shí)例,它是 Error 的一個(gè)子類抽活,用于把單一的錯(cuò)誤集合在一起
Promise.any()跟Promise.race()方法很像硫戈,只有一點(diǎn)不同,就是Promise.any()不會(huì)因?yàn)槟硞€(gè) Promise 變成rejected狀態(tài)而結(jié)束下硕,必須等到所有參數(shù) Promise 變成rejected狀態(tài)才會(huì)結(jié)束丁逝。

4.邏輯運(yùn)算符和賦值表達(dá)式(&&=汁胆,||=,??=)

&&=
邏輯與賦值 x &&= y等效于:
x && (x = y);
上面的意思是霜幼,當(dāng)x為真時(shí)嫩码,x=y。具體請(qǐng)看下面的示例:

let a = 1;
let b = 0;
a &&= 2;
console.log(a); // 2
b &&= 2;
console.log(b);  // 0

||=
邏輯或賦值(x ||= y)運(yùn)算僅在 x 為false時(shí)賦值罪既。
x ||= y 等同于:x || (x = y);

const a = { duration: 50, title: '' };
a.duration ||= 10;
console.log(a.duration); // 50
a.title ||= 'title is empty.';
console.log(a.title); // "title is empty"

??=
邏輯空賦值運(yùn)算符 (x ??= y) 僅在 x 是 null 或 undefined 時(shí)對(duì)其賦值铸题。

const a = { duration: 50 };
a.duration ??= 10;
console.log(a.duration); // 50
a.speed ??= 25;
console.log(a.speed); // 25

5.FinalizationRegistry

FinalizationRegistry 提供了這樣的一種方法:當(dāng)一個(gè)在注冊(cè)表中注冊(cè)的對(duì)象被回收時(shí),請(qǐng)求在某個(gè)時(shí)間點(diǎn)上調(diào)用一個(gè)清理回調(diào)
你可以通過調(diào)用register方法萝衩,注冊(cè)任何你想要清理回調(diào)的對(duì)象回挽,傳入該對(duì)象和所含的值

let obj = { name: "why", age: 18 }
let info = { name: "kobe", age: 30 }
const finalRegistry = new FinalizationRegistry((value) => {
  console.log("某一個(gè)對(duì)象被回收了:", value)
})
finalRegistry.register(obj, "why")
finalRegistry.register(info, "kobe")
// obj = null
info = null

6.WeakRefs

新的類 WeakRefs。允許創(chuàng)建對(duì)象的弱引用猩谊。這樣就能夠在跟蹤現(xiàn)有對(duì)象時(shí)不會(huì)阻止對(duì)其進(jìn)行垃圾回收千劈。對(duì)于緩存和對(duì)象映射非常有用。
必須用 new關(guān)鍵字創(chuàng)建新的 WeakRef牌捷,并把某些對(duì)象作為參數(shù)放入括號(hào)中墙牌。當(dāng)你想讀取引用(被引用的對(duì)象)時(shí),可以通過在弱引用上調(diào)用 deref() 來實(shí)現(xiàn)暗甥。
如果我們默認(rèn)將一個(gè)對(duì)象賦值給另外一個(gè)引用喜滨,那么這個(gè)引用是一個(gè)強(qiáng)引用
如果我們希望是一個(gè)弱引用的話,可以使用WeakRef

let info = { name: "why", age: 18 }
let obj = new WeakRef(info)
let obj2 = new WeakRef(info)
const finalRegistry = new FinalizationRegistry(() => {
  console.log("對(duì)象被回收~")
})
finalRegistry.register(info, "info")
setTimeout(() => {
  info = null
}, 2000)
setTimeout(() => {
  console.log(obj.deref().name, obj.deref().age)
}, 4000)

7.Intl.ListFormat

Intl.ListFormat 用來處理和多語(yǔ)言相關(guān)的對(duì)象格式化操作
Intl.ListFormat 參數(shù)/用法

new Intl.ListFormat([locales[, options]])

輸出處理過后的字符串
示例
//不允許存在數(shù)字,如有空格撤防,不會(huì)忽略空格

let strArr = ["xiaoming", "小明", "小紅", "XXMM"]; 
    let EnForm = new Intl.ListFormat("en",{
      localeMatcher:'lookup',
      style:'short',
      type:'disjunction'
    }).format(strArr);
    let cnForm = new Intl.ListFormat("zh-cn",{
      localeMatcher:'lookup',
      style:'short',
      type:'disjunction'
    }).format(strArr);
    // lookup/best fit + long + conjunction  輸出:
    // console.log("en", EnForm); // xiaoming, 小明, 小紅, and XXMM
    // console.log("cn", cnForm); // xiaoming虽风、小明、小紅和XXMM

    // lookup/best fit + short/long + disjunction   輸出:
    // console.log("en", EnForm); // xiaoming, 小明, 小紅, or XXMM
    // console.log("cn", cnForm); // xiaoming寄月、小明辜膝、小紅和XXMM

    // lookup/best fit + short + conjunction   輸出:
    // console.log("en", EnForm); // xiaoming, 小明, 小紅, & XXMM
    // console.log("cn", cnForm); // xiaoming、小明漾肮、小紅和XXMM

    // lookup/best fit + narrow + unit  輸出:
    //  console.log("en", EnForm); // xiaoming 小明 小紅 XXMM
    // console.log("cn", cnForm); // xiaoming小明小紅XXMM

8. Intl.DateTimeFormat() 是什么厂抖?

可以用來處理多語(yǔ)言下的時(shí)間日期格式化函數(shù)。與 moment.js 時(shí)間插件相似
Intl.DateTimeFormat 參數(shù)/用法

new Intl.DateTimeFormat([locales[, options]])

示例

 let date = new Date(); //獲取本機(jī)當(dāng)前時(shí)間
// 粗暴用法 獲取 年月日+時(shí)間
 let dateShort = { timeStyle: "medium", dateStyle: "short" };
 let dateMedium = { timeStyle: "medium", dateStyle: "medium" };
 console.log(new Intl.DateTimeFormat('zh-cn',dateShort).format(date)); // 2022/8/5 15:27:17
 console.log(new Intl.DateTimeFormat('zh-cn',dateMedium).format(date)); // 2022年8月5日 15:27:28

 // 精確用法 獲取 公元+星期+年月日+時(shí)間
 // 不傳克懊,取默認(rèn)的時(shí)間格式
 console.log(new Intl.DateTimeFormat().format(date)); // 2022/8/5
  let options1 = {
    year: "numeric",
    month: "numeric", 
    hour: "numeric",
    minute: "numeric",
    second: "numeric",
    hour12: false, //是否為 12 小時(shí)制
  }
  console.log(new Intl.DateTimeFormat("de-DE", options1).format(date)); // de-DE(德語(yǔ)) Freitag, 5. August 2022

  let options2 = {
      era: "long", // 公元  locales如果為中文忱辅,切換任何參數(shù)都是公元,反之谭溉,才會(huì)有長(zhǎng)短顯示的區(qū)別
      weekday: "long", // 星期幾
      year: "numeric",
      month: "numeric", // long 打印: 5. August 2022 um 14:31:44, short 打忧蕉:5. Aug. 2022, 14:32:37, narrow 打印:5. A 2022, 14:35:58
      day: "numeric",
      hour: "numeric",
      minute: "numeric",
      second: "numeric",
      hour12: false,
    };
    console.log(new Intl.DateTimeFormat("zh-cn", options2).format(date)); // 公元2022年8月5日星期五 15:31:32

    let options3 = {
      timeStyle: "medium",
      dateStyle: "short",
    };
    console.log(new Intl.DateTimeFormat("zh-cn", options3).format(date)); // 2022/8/5 14:27:59

9. Intl.RelativeTimeFormat()

處理時(shí)間格式扮念,轉(zhuǎn)換為昨天/前天/一天前/季度等
Intl.RelativeTimeFormat() 參數(shù)/用法

new Intl.RelativeTimeFormat([locales[, options]])

const tf = new Intl.RelativeTimeFormat(“zh-cn”);
console.log( tf.format(-10, “year”) );
// output :: 10年前

示例

// options 不寫表示默認(rèn)項(xiàng)
 const tf = new Intl.RelativeTimeFormat("zh-cn");
    // output :: 10年前
    console.log(tf.format(-10, "year"));
    // output :: 5個(gè)月前
    console.log(tf.format(-5, "month"));
    // output :: 2個(gè)季度后
    console.log(tf.format(2, "quarter"));
    // output :: 2周后
    console.log(tf.format(2, "week"));
    // output :: 2天前
    console.log(tf.format(-2, "day"));
     // output :: 8小時(shí)后
    console.log(tf.format(8, "hour"));
    // output :: 15分鐘前
    console.log(tf.format(-15, "minute"));
    // output :: 2秒鐘后
    console.log(tf.format(2, "second"));

1.空值合并運(yùn)算符

空值合并操作符( ?? )是一個(gè)邏輯操作符损搬,當(dāng)左側(cè)的操作數(shù)為 null或者undefined時(shí),返回其右側(cè)操作數(shù),否則返回左側(cè)操作數(shù)场躯。

const foo = undefined ?? "foo"
const bar = null ?? "bar"
console.log(foo) // foo
console.log(bar) // bar

與邏輯或操作符(||)不同,邏輯或操作符會(huì)在左側(cè)操作數(shù)為假值時(shí)返回右側(cè)操作數(shù)旅挤。也就是說踢关,如果使用 || 來為某些變量設(shè)置默認(rèn)值,可能會(huì)遇到意料之外的行為粘茄。比如為假值(例如'',0,NaN,false)時(shí)签舞。見下面的例子

const foo = "" ?? 'default string';
const foo2 = "" || 'default string';
console.log(foo); // ""
console.log(foo2); // "default string"

const baz = 0 ?? 42;
const baz2 = 0 || 42;
console.log(baz); // 0
console.log(baz2); // 42

2.可選鏈

可選鏈操作符( ?. )允許讀取位于連接對(duì)象鏈深處的屬性的值,而不必明確驗(yàn)證鏈中的每個(gè)引用是否有效柒瓣。?. 操作符的功能類似于 . 鏈?zhǔn)讲僮鞣宕睿煌幵谟冢谝脼?null 或者 undefined 的情況下不會(huì)引起錯(cuò)誤芙贫,該表達(dá)式短路返回值是 undefined搂鲫。與函數(shù)調(diào)用一起使用時(shí),如果給定的函數(shù)不存在磺平,則返回 undefined魂仍。
當(dāng)嘗試訪問可能不存在的對(duì)象屬性時(shí),可選鏈操作符將會(huì)使表達(dá)式更短拣挪、更簡(jiǎn)明擦酌。在探索一個(gè)對(duì)象的內(nèi)容時(shí),如果不能確定哪些屬性必定存在菠劝,可選鏈操作符也是很有幫助的赊舶。

const user = {
    address: {
        street: 'xx街道',
        getNum() {
            return '80號(hào)'
        }
    }
}

在之前的語(yǔ)法中,想獲取到深層屬性或方法赶诊,不得不做前置校驗(yàn)笼平,否則很容易命中 Uncaught TypeError: Cannot read property... 這種錯(cuò)誤,這極有可能讓你整個(gè)應(yīng)用掛掉甫何。

const street = user && user.address && user.address.street
const num = user && user.address && user.address.getNum && user.address.getNum()
console.log(street, num)

用了 Optional Chaining 出吹,上面代碼會(huì)變成

const street2 = user?.address?.street
const num2 = user?.address?.getNum?.()
console.log(street2, num2)

常見用法

// 對(duì)象中使用
  let obj = {
    name: "jimmy",
    age: "18",
  };
  let property = "age";
  let name = obj?.name;
  let age = obj?.age;
  let ages = obj?.[property];
  let sex = obj?.sex;
  console.log(name); // jimmy
  console.log(age); // 18
  console.log(ages); // 18
  console.log(sex); // undefined
  // 數(shù)組中使用
  let arr = [1,2,2];
  let arrayItem = arr?.[42]; // undefined
  // 函數(shù)中使用
  let obj = {
   func: function () {
     console.log("I am func");
   },
  };
  obj?.func(); // I am func

與空值合并操作符一起使用

let customer = {
  name: "jimmy",
  details: { age: 18 }
};
let customerCity = customer?.city ?? "成都";
console.log(customerCity); // "成都"

注意點(diǎn):可選鏈不能用于賦值
let object = {};
object?.property = 1; // Uncaught SyntaxError: Invalid left-hand side in assignment

3.globalThis

在以前,從不同的 JavaScript 環(huán)境中獲取全局對(duì)象需要不同的語(yǔ)句辙喂。在 Web 中捶牢,可以通過 window、self 取到全局對(duì)象巍耗,在 Node.js 中秋麸,它們都無法獲取,必須使用 global炬太。
在松散模式下灸蟆,可以在函數(shù)中返回 this 來獲取全局對(duì)象,但是在嚴(yán)格模式和模塊環(huán)境下亲族,this 會(huì)返回 undefined炒考。
以前想要獲取全局對(duì)象可缚,可通過一個(gè)全局函數(shù)

const getGlobal = () => {
    if (typeof self !== 'undefined') {
        return self
    }
    if (typeof window !== 'undefined') {
        return window
    }
    if (typeof global !== 'undefined') {
        return global
    }
    throw new Error('無法找到全局對(duì)象')
}
const globals = getGlobal()
console.log(globals)

現(xiàn)在globalThis 提供了一個(gè)標(biāo)準(zhǔn)的方式來獲取不同環(huán)境下的全局 this 對(duì)象(也就是全局對(duì)象自身)。不像 window 或者 self 這些屬性斋枢,它確绷泵遥可以在有無窗口的各種環(huán)境下正常工作。所以瓤帚,你可以安心的使用 globalThis描姚,不必?fù)?dān)心它的運(yùn)行環(huán)境。

為便于記憶戈次,你只需要記住轩勘,全局作用域中的 this 就是globalThis。以后就用globalThis就行了怯邪。
image.png

4.BigInt

BigInt 是一種內(nèi)置對(duì)象绊寻,它提供了一種方法來表示大于 2的53次方 的整數(shù)。這原本是 Javascript中可以用 Number 表示的最大數(shù)字擎颖。BigInt 可以表示任意大的整數(shù)榛斯。
使用 BigInt 有兩種方式:
方式一:數(shù)字后面增加n

const bigInt = 9007199254740993n
console.log(bigInt)
console.log(typeof bigInt) // bigint
// `BigInt` 和 [`Number`]不是嚴(yán)格相等的,但是寬松相等的搂捧。
console.log(1n == 1) // true
console.log(1n === 1) // false
// `Number` 和 `BigInt` 可以進(jìn)行比較驮俗。
1n < 2 //  true
2n > 1 //  true

方式二:使用 BigInt 函數(shù)

const bigIntNum = BigInt(9007199254740993)
console.log(bigIntNum)

運(yùn)算

let number = BigInt(2);
let a = number + 2n; 
let b = number * 10n;
let c = number - 10n; 
console.log(a);// 4n
console.log(b); // 20n
console.log(c);// -8n

注意點(diǎn)
BigInt不能用于 [Math] 對(duì)象中的方法;不能和任何 [Number] 實(shí)例混合運(yùn)算允跑,兩者必須轉(zhuǎn)換成同一種類型王凑。在兩種類型來回轉(zhuǎn)換時(shí)要小心,因?yàn)?BigInt 變量在轉(zhuǎn)換成 [Number] 變量時(shí)可能會(huì)丟失精度聋丝。

5.String.prototype.matchAll()

matchAll()
方法返回一個(gè)包含所有匹配正則表達(dá)式的結(jié)果及分組捕獲組的迭代器索烹。

const regexp = /t(e)(st(\d?))/g;
const str = 'test1test2';
const array = [...str.matchAll(regexp)];
console.log(array[0]);  // ["test1", "e", "st1", "1"]
console.log(array[1]); // ["test2", "e", "st2", "2"]

6.Promise.allSettled()

我們都知道 Promise.all() 具有并發(fā)執(zhí)行異步任務(wù)的能力。但它的最大問題就是如果其中某個(gè)任務(wù)出現(xiàn)異常(reject)弱睦,所有任務(wù)都會(huì)掛掉百姓,Promise直接進(jìn)入reject 狀態(tài)。
場(chǎng)景:現(xiàn)在頁(yè)面上有三個(gè)請(qǐng)求况木,分別請(qǐng)求不同的數(shù)據(jù)垒拢,如果一個(gè)接口服務(wù)異常,整個(gè)都是失敗的火惊,都無法渲染出數(shù)據(jù),我們需要一種機(jī)制求类,如果并發(fā)任務(wù)中,無論一個(gè)任務(wù)正骋倌停或者異常尸疆,都會(huì)返回對(duì)應(yīng)的的狀態(tài),這就是Promise.allSettled的作用

const promise1 = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("promise1");
      //   reject("error promise1 ");
    }, 3000);
  });
};
const promise2 = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("promise2");
      //   reject("error promise2 ");
    }, 1000);
  });
};
const promise3 = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      //   resolve("promise3");
      reject("error promise3 ");
    }, 2000);
  });
};
//  Promise.all 會(huì)走到catch里面
Promise.all([promise1(), promise2(), promise3()])
  .then((res) => {
    console.log(res); 
  })
  .catch((error) => {
    console.log("error", error); // error promise3 
  });
// Promise.allSettled 不管有沒有錯(cuò)誤,三個(gè)的狀態(tài)都會(huì)返回
Promise.allSettled([promise1(), promise2(), promise3()])
  .then((res) => {
    console.log(res);  
    // 打印結(jié)果 
    // [
    //    {status: 'fulfilled', value: 'promise1'}, 
    //    {status: 'fulfilled',value: 'promise2'},
    //    {status: 'rejected', reason: 'error promise3 '}
    // ]
  })
  .catch((error) => {
    console.log("error", error); 
  });

7.Dynamic Import(按需 import)

import()可以在需要的時(shí)候寿弱,再加載某個(gè)模塊犯眠。

button.addEventListener('click', event => {
  import('./dialogBox.js')
  .then(dialogBox => {
    dialogBox.open();
  })
  .catch(error => {
    /* Error handling */
  })
});

上面代碼中,import()方法放在click事件的監(jiān)聽函數(shù)之中症革,只有用戶點(diǎn)擊了按鈕阔逼,才會(huì)加載這個(gè)模塊。

1.Object.fromEntries()

方法 Object.fromEntries() 把鍵值對(duì)列表轉(zhuǎn)換為一個(gè)對(duì)象地沮,這個(gè)方法是和Object.entries() 相對(duì)的。

Object.fromEntries([
    ['foo', 1],
    ['bar', 2]
])
// {foo: 1, bar: 2}

案例1:Object 轉(zhuǎn)換操作

const obj = {
    name: 'jimmy',
    age: 18
}
const entries = Object.entries(obj)
console.log(entries)
// [Array(2), Array(2)]
const fromEntries = Object.fromEntries(entries)
console.log(fromEntries)
// {name: "jimmy", age: 18}

案例2:Map 轉(zhuǎn) Object

const map = new Map()
map.set('name', 'jimmy')
map.set('age', 18)
console.log(map) // {'name' => 'jimmy', 'age' => 18}
const obj = Object.fromEntries(map)
console.log(obj)
// {name: "jimmy", age: 18}

案例3:過濾
course表示所有課程羡亩,想請(qǐng)求課程分?jǐn)?shù)大于80的課程組成的對(duì)象:

const course = {
    math: 80,
    english: 85,
    chinese: 90
}
const res = Object.entries(course).filter(([key, val]) => val > 80)
console.log(res) // [ [ 'english', 85 ], [ 'chinese', 90 ] ]
console.log(Object.fromEntries(res)) // { english: 85, chinese: 90 }

案例4:url的search參數(shù)轉(zhuǎn)換

// let url = "https://www.baidu.com?name=jimmy&age=18&height=1.88"
// queryString 為 window.location.search
const queryString = "?name=jimmy&age=18&height=1.88";
const queryParams = new URLSearchParams(queryString);
const paramObj = Object.fromEntries(queryParams);
console.log(paramObj); // { name: 'jimmy', age: '18', height: '1.88' }
console.log([...queryParams.entries()]);// [ ['name', 'jimmy'], ['age', '18'], ['height', '1.88']]

2.Array.prototype.flat()

語(yǔ)法

let newArray = arr.flat([depth])

depth 可選
指定要提取嵌套數(shù)組的結(jié)構(gòu)深度摩疑,默認(rèn)值為 1懦胞。
示例
flat() 方法會(huì)按照一個(gè)可指定的深度遞歸遍歷數(shù)組粉渠,并將所有元素與遍歷到的子數(shù)組中的元素合并為一個(gè)新數(shù)組返回昧绣。

const arr1 = [0, 1, 2, [3, 4]];
console.log(arr1.flat());  //  [0, 1, 2, 3, 4]
const arr2 = [0, 1, 2, [[[3, 4]]]];
console.log(arr2.flat(2));  //  [0, 1, 2, [3, 4]]
//使用 Infinity仓犬,可展開任意深度的嵌套數(shù)組
var arr4 = [1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]];
arr4.flat(Infinity); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// `flat()` 方法會(huì)移除數(shù)組中的空項(xiàng):
var arr5 = [1, 2, , 4, 5];
arr5.flat(); // [1, 2, 4, 5]

3.Array.prototype.flatMap()

flatMap() 方法首先使用映射函數(shù)映射每個(gè)元素挠蛉,然后將結(jié)果壓縮成一個(gè)新數(shù)組也糊。從方法的名字上也可以看出來它包含兩部分功能一個(gè)是 map垛吗,一個(gè)是 flat(深度為1)残腌。

var new_array = arr.flatMap(function callback(currentValue[, index[, array]]) {
    // 返回新數(shù)組的元素
}[, thisArg])

callback
可以生成一個(gè)新數(shù)組中的元素的函數(shù)瓦灶,可以傳入三個(gè)參數(shù):
currentValue:當(dāng)前正在數(shù)組中處理的元素
index:可選 數(shù)組中正在處理的當(dāng)前元素的索引鸠删。
array:可選 被調(diào)用的 map 數(shù)組
thisArg可選
執(zhí)行 callback 函數(shù)時(shí) 使用的this 值。
示例

const numbers = [1, 2, 3]
numbers.map(x => [x * 2]) // [[2], [4], [6]]
numbers.flatMap(x => [x * 2]) // [2, 4, 6]

這個(gè)示例可以簡(jiǎn)單對(duì)比下 map 和 flatMap 的區(qū)別贼陶。當(dāng)然還可以看下下面的示例:

let arr = ['今天天氣不錯(cuò)', '', '早上好']
arr.map(s => s.split(''))
// [["今", "天", "天", "氣", "不", "錯(cuò)"],[""],["早", "上", "好"]]
arr.flatMap(s => s.split(''))
// ["今", "天", "天", "氣", "不", "錯(cuò)", "", "早", "上", "好"]

flatMap 方法與 map 方法和深度depth為1的 flat 幾乎相同.

4.String.prototype.trimStart()

trimStart() 方法從字符串的開頭刪除空格刃泡,trimLeft()是此方法的別名。

let str = '   foo  '
console.log(str.length) // 8
str = str.trimStart() // 或str.trimLeft()
console.log(str.length) // 5

5.String.prototype.trimEnd()

trimEnd() 方法從一個(gè)字符串的右端移除空白字符碉怔,trimRight 是 trimEnd 的別名烘贴。

let str = '   foo  '
console.log(str.length) // 8
str = str.trimEnd() // 或str.trimRight()
console.log(str.length) // 6

6.可選的Catch Binding

在 ES10 之前我們都是這樣捕獲異常的:

try {
    // tryCode
} catch (err) {
    // catchCode
}

在這里 err 是必須的參數(shù),在 ES10 可以省略這個(gè)參數(shù):

try {
    console.log('Foobar')
} catch {
    console.error('Bar')
}

應(yīng)用
驗(yàn)證參數(shù)是否為json格式
這個(gè)需求我們只需要返回true或false撮胧,并不關(guān)心catch的參數(shù)桨踪。

const validJSON = json => {
    try {
        JSON.parse(json)
        return true
    } catch {
        return false
    }
}

7.Symbol.prototype.description

我們知道,Symbol 的描述只被存儲(chǔ)在內(nèi)部的 Description 芹啥,沒有直接對(duì)外暴露锻离,我們只有調(diào)用 Symbol 的 toString() 時(shí)才可以讀取這個(gè)屬性:

const name = Symbol('es')
console.log(name.toString()) // Symbol(es)
console.log(name) // Symbol(es)
console.log(name === 'Symbol(es)') // false
console.log(name.toString() === 'Symbol(es)') // true

現(xiàn)在可以通過 description 方法獲取 Symbol 的描述:

const name = Symbol('es')
console.log(name.description) // es
name.description = "es2" // 只讀屬性 并不能修改描述符
console.log(name.description === 'es') // true
// 如果沒有描述符 輸出undefined
const s2 = Symbol()
console.log(s2.description) // undefined

8.JSON.stringify() 增強(qiáng)能力

JSON.stringify 在 ES10 修復(fù)了對(duì)于一些超出范圍的 Unicode 展示錯(cuò)誤的問題。因?yàn)?JSON 都是被編碼成 UTF-8叁征,所以遇到 0xD800–0xDFFF 之內(nèi)的字符會(huì)因?yàn)闊o法編碼成 UTF-8 進(jìn)而導(dǎo)致顯示錯(cuò)誤纳账。在 ES10 它會(huì)用轉(zhuǎn)義字符的方式來處理這部分字符而非編碼的方式,這樣就會(huì)正常顯示了捺疼。

// \uD83D\uDE0E  emoji 多字節(jié)的一個(gè)字符
console.log(JSON.stringify('\uD83D\uDE0E')) // 打印出笑臉
// 如果我們只去其中的一部分  \uD83D 這其實(shí)是個(gè)無效的字符串
// 之前的版本 疏虫,這些字符將替換為特殊字符,而現(xiàn)在將未配對(duì)的代理代碼點(diǎn)表示為JSON轉(zhuǎn)義序列
console.log(JSON.stringify('\uD83D')) // "\ud83d"

9.修訂 Function.prototype.toString()

以前函數(shù)的toString方法來自O(shè)bject.prototype.toString(),現(xiàn)在的 Function.prototype.toString() 方法返回一個(gè)表示當(dāng)前函數(shù)源代碼的字符串。以前只會(huì)返回這個(gè)函數(shù)卧秘,不包含注釋呢袱、空格等。

function foo() {
    // es10新特性
    console.log('imooc')
}
console.log(foo.toString()) 
// 打印如下
// function foo() {
//  // es10新特性
//  console.log("imooc");
// }

將返回注釋翅敌、空格和語(yǔ)法等詳細(xì)信息羞福。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市蚯涮,隨后出現(xiàn)的幾起案子治专,更是在濱河造成了極大的恐慌,老刑警劉巖遭顶,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件张峰,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡棒旗,警方通過查閱死者的電腦和手機(jī)喘批,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來铣揉,“玉大人饶深,你說我怎么就攤上這事」涔埃” “怎么了敌厘?”我有些...
    開封第一講書人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)朽合。 經(jīng)常有香客問我额湘,道長(zhǎng),這世上最難降的妖魔是什么旁舰? 我笑而不...
    開封第一講書人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任锋华,我火速辦了婚禮,結(jié)果婚禮上箭窜,老公的妹妹穿的比我還像新娘毯焕。我一直安慰自己,他們只是感情好磺樱,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開白布纳猫。 她就那樣靜靜地躺著,像睡著了一般竹捉。 火紅的嫁衣襯著肌膚如雪芜辕。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,692評(píng)論 1 305
  • 那天块差,我揣著相機(jī)與錄音侵续,去河邊找鬼倔丈。 笑死,一個(gè)胖子當(dāng)著我的面吹牛状蜗,可吹牛的內(nèi)容都是我干的需五。 我是一名探鬼主播,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼轧坎,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼宏邮!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起缸血,我...
    開封第一講書人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤蜜氨,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后捎泻,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體记劝,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年族扰,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片定欧。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡渔呵,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出砍鸠,到底是詐尸還是另有隱情扩氢,我是刑警寧澤,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布爷辱,位于F島的核電站录豺,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏饭弓。R本人自食惡果不足惜双饥,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望弟断。 院中可真熱鬧咏花,春花似錦、人聲如沸阀趴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)刘急。三九已至棚菊,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間叔汁,已是汗流浹背统求。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工检碗, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人球订。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓后裸,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親冒滩。 傳聞我的和親對(duì)象是個(gè)殘疾皇子微驶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355

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