10分鐘學會ES7+ES8

来源:http://www.cnblogs.com/zhuanzhuanfe/archive/2017/09/08/7493433.html
-Advertisement-
Play Games

撰文為何 身為一個前端開發者,ECMAScript(以下簡稱ES)早已廣泛應用在我們的工作當中。瞭解ECMA機構流程的人應該知道,標準委員會會在每年的6月份正式發佈一次規範的修訂,而這次的發佈也將作為當年的正式版本。以後的改動,都會基於上一版本進行修改。所以,我們這次就基於ES6的版本對ES7、ES ...


撰文為何

身為一個前端開發者,ECMAScript(以下簡稱ES)早已廣泛應用在我們的工作當中。瞭解ECMA機構流程的人應該知道,標準委員會會在每年的6月份正式發佈一次規範的修訂,而這次的發佈也將作為當年的正式版本。以後的改動,都會基於上一版本進行修改。所以,我們這次就基於ES6的版本對ES7、ES8版本的新增以及修改內容,做一次簡要的總結,方便我們快速開發。

ES7新特性

ES7在ES6的基礎上添加了三項內容:求冪運算符(**)Array.prototype.includes()方法、函數作用域中嚴格模式的變更。

Array.prototype.includes()方法

includes()的作用,是查找一個值在不在數組裡,若在,則返回true,反之返回false。 基本用法:

['a', 'b', 'c'].includes('a')     // true
['a', 'b', 'c'].includes('d')     // false

 

Array.prototype.includes()方法接收兩個參數:要搜索的值和搜索的開始索引。當第二個參數被傳入時,該方法會從索引處開始往後搜索(預設索引值為0)。若搜索值在數組中存在則返回true,否則返回false。 且看下麵示例:

['a', 'b', 'c', 'd'].includes('b')         // true
['a', 'b', 'c', 'd'].includes('b', 1)      // true
['a', 'b', 'c', 'd'].includes('b', 2)      // false

 

那麼,我們會聯想到ES6里數組的另一個方法indexOf,下麵的示例代碼是等效的:

['a', 'b', 'c'].includes('a')          //true
['a', 'b', 'c'].indexOf('a') > -1      //true

 

此時,就有必要來比較下兩者的優缺點和使用場景了。

  • 簡便性

從這一點上來說,includes略勝一籌。熟悉indexOf的同學都知道,indexOf返回的是某個元素在數組中的下標值,若想判斷某個元素是否在數組裡,我們還需要做額外的處理,即判斷該返回值是否>-1。而includes則不用,它直接返回的便是Boolean型的結果。

  • 精確性

兩者使用的都是 === 操作符來做值的比較。但是includes()方法有一點不同,兩個NaN被認為是相等的,即使在NaN === NaN結果是false的情況下。這一點和indexOf()的行為不同,indexOf()嚴格使用===判斷。請看下麵示例代碼:

let demo = [1, NaN, 2, 3]

demo.indexOf(NaN)        //-1
demo.includes(NaN)       //true

 

上述代碼中,indexOf()方法返回-1,即使NaN存在於數組中,而includes()則返回了true。

提示:由於它對NaN的處理方式與indexOf不同,假如你只想知道某個值是否在數組中而並不關心它的索引位置,建議使用includes()。如果你想獲取一個值在數組中的位置,那麼你只能使用indexOf方法。

includes()還有一個怪異的點需要指出,在判斷 +0 與 -0 時,被認為是相同的。

[1, +0, 3, 4].includes(-0)    //true
[1, +0, 3, 4].indexOf(-0)     //1

 

在這一點上,indexOf()includes()的處理結果是一樣的,前者同樣會返回 +0 的索引值。

註意:在這裡,需要註意一點,includes()只能判斷簡單類型的數據,對於複雜類型的數據,比如對象類型的數組,二維數組,這些,是無法判斷的。

求冪運算符(**)

基本用法

3 ** 2           // 9

效果同:

Math.pow(3, 2)   // 9

** 是一個用於求冪的中綴運算元,比較可知,中綴符號比函數符號更簡潔,這也使得它更為可取。 下麵讓我們擴展下思路,既然說**是一個運算符,那麼它就應該能滿足類似加等的操作,我們姑且稱之為冪等,例如下麵的例子,a的值依然是9:

let a = 3
a **= 2
// 9

 

對比下其他語言的指數運算符:

  • Python: x ** y
  • CoffeeScript: x ** y
  • F#: x ** y
  • Ruby: x ** y
  • Perl: x ** y
  • Lua, Basic, MATLAB: x ^ y

不難發現,ES的這個新特性是從其他語言(Python,Ruby等)模仿而來的。

ES8新特性

非同步函數(Async functions)

為什麼要引入async

眾所周知,JavaScript語言的執行環境是“單線程”的,那麼非同步編程對JavaScript語言來說就顯得尤為重要。以前我們大多數的做法是使用回調函數來實現JavaScript語言的非同步編程。回調函數本身沒有問題,但如果出現多個回調函數嵌套,例如:進入某個頁面,需要先登錄,拿到用戶信息之後,調取用戶商品信息,代碼如下:

this.$http.jsonp('/login', (res) => {
  this.$http.jsonp('/getInfo', (info) => {
    // do something
  })
})

 

假如上面還有更多的請求操作,就會出現多重嵌套。代碼很快就會亂成一團,這種情況就被稱為“回調函數地獄”(callback hell)。

於是,我們提出了Promise,它將回調函數的嵌套,改成了鏈式調用。寫法如下:

var promise = new Promise((resolve, reject) => {
  this.login(resolve)
})
.then(() => this.getInfo())
.catch(() => { console.log("Error") })

 

從上面可以看出,Promise的寫法只是回調函數的改進,使用then方法,只是讓非同步任務的兩段執行更清楚而已。Promise的最大問題是代碼冗餘,請求任務多時,一堆的then,也使得原來的語義變得很不清楚。此時我們引入了另外一種非同步編程的機制:Generator。

Generator 函數是一個普通函數,但是有兩個特征。一是,function關鍵字與函數名之間有一個星號;二是,函數體內部使用yield表達式,定義不同的內部狀態(yield在英語里的意思就是“產出”)。一個簡單的例子用來說明它的用法:

function* helloWorldGenerator() {
  yield 'hello';
  yield 'world';
  return 'ending';
}

var hw = helloWorldGenerator();

 

上面代碼定義了一個 Generator 函數helloWorldGenerator,它內部有兩個yield表達式(hello和world),即該函數有三個狀態:hello,world 和 return 語句(結束執行)。Generator 函數的調用方法與普通函數一樣,也是在函數名後面加上一對圓括弧。不同的是,調用 Generator 函數後,該函數並不執行,返回的也不是函數運行結果,而是一個指向內部狀態的指針對象,必須調用遍歷器對象的next方法,使得指針移向下一個狀態。也就是說,每次調用next方法,內部指針就從函數頭部或上一次停下來的地方開始執行,直到遇到下一個yield表達式(或return語句)為止。換言之,Generator 函數是分段執行的,yield表達式是暫停執行的標記,而next方法可以恢復執行。上述代碼分步執行如下:

hw.next()
// { value: 'hello', done: false }

hw.next()
// { value: 'world', done: false }

hw.next()
// { value: 'ending', done: true }

hw.next()
// { value: undefined, done: true }

 

Generator函數的機制更符合我們理解的非同步編程思想。

用戶登錄的例子,我們用Generator來寫,如下:

var gen = function* () {
  const f1 = yield this.login()
  const f2 = yield this.getInfo()
};

 

雖然Generator將非同步操作表示得很簡潔,但是流程管理卻不方便(即何時執行第一階段、何時執行第二階段)。此時,我們便希望能出現一種能自動執行Generator函數的方法。我們的主角來了:async/await。

ES8引入了async函數,使得非同步操作變得更加方便。簡單說來,它就是Generator函數的語法糖。

async function asyncFunc(params) {
  const result1 = await this.login()
  const result2 = await this.getInfo()
}

 

是不是更加簡潔易懂呢?

變體

非同步函數存在以下四種使用形式:

  • 函數聲明: async function foo() {}
  • 函數表達式: const foo = async function() {}
  • 對象的方式: let obj = { async foo() {} }
  • 箭頭函數: const foo = async () => {}
常見用法彙總

處理單個非同步結果:

async function asyncFunc() {
  const result = await otherAsyncFunc();
  console.log(result);
}

 

順序處理多個非同步結果:

async function asyncFunc() {
  const result1 = await otherAsyncFunc1();
  console.log(result1);
  const result2 = await otherAsyncFunc2();
  console.log(result2);
}

 

並行處理多個非同步結果:

async function asyncFunc() {
  const [result1, result2] = await Promise.all([
    otherAsyncFunc1(),
    otherAsyncFunc2()
  ]);
  console.log(result1, result2);
}

 

處理錯誤:

async function asyncFunc() {
  try {
    await otherAsyncFunc();
  } catch (err) {
    console.error(err);
  }
}

 

若想進一步瞭解async的具體實踐,可參見阮一峰的博客文章,鏈接奉上:http://es6.ruanyifeng.com/#docs/async

Object.entries()和Object.values()

Object.entries()

如果一個對象是具有鍵值對的數據結構,則每一個鍵值對都將會編譯成一個具有兩個元素的數組,這些數組最終會放到一個數組中,返回一個二維數組。簡言之,該方法會將某個對象的可枚舉屬性與值按照二維數組的方式返回。若目標對象是數組時,則會將數組的下標作為鍵值返回。例如:

Object.entries({ one: 1, two: 2 })    //[['one', 1], ['two', 2]]
Object.entries([1, 2])                //[['0', 1], ['1', 2]]

 

註意:鍵值對中,如果鍵的值是Symbol,編譯時將會被忽略。例如:

Object.entries({ [Symbol()]: 1, two: 2 })       //[['two', 2]]

Object.entries()返回的數組的順序與for-in迴圈保持一致,即如果對象的key值是數字,則返回值會對key值進行排序,返回的是排序後的結果。例如:

Object.entries({ 3: 'a', 4: 'b', 1: 'c' })    //[['1', 'c'], ['3', 'a'], ['4', 'b']]

 

使用Object.entries(),我們還可以進行對象屬性的遍歷。例如:

let obj = { one: 1, two: 2 };
for (let [k,v] of Object.entries(obj)) {
  console.log(`${JSON.stringify(k)}: ${JSON.stringify(v)}`);
}

//輸出結果如下:
'one': 1
'two': 2

 

Object.values()

它的工作原理跟Object.entries()很像,顧名思義,它只返回自己的鍵值對中屬性的值。它返回的數組順序,也跟Object.entries()保持一致。

Object.values({ one: 1, two: 2 })            //[1, 2]
Object.values({ 3: 'a', 4: 'b', 1: 'c' })    //['c', 'a', 'b']

 

字元串填充:padStart和padEnd

ES8提供了新的字元串方法-padStart和padEnd。padStart函數通過填充字元串的首部來保證字元串達到固定的長度,反之,padEnd是填充字元串的尾部來保證字元串的長度的。該方法提供了兩個參數:字元串目標長度和填充欄位,其中第二個參數可以不填,預設情況下使用空格填充。

'Vue'.padStart(10)           //'       Vue'
'React'.padStart(10)         //'     React'
'JavaScript'.padStart(10)    //'JavaScript'

 

可以看出,多個數據如果都採用同樣長度的padStart,相當於將呈現內容右對齊。

上面示例中我們只定義了第一個參數,那麼我們現在來看看第二個參數,我們可以指定字元串來代替空字元串。

'Vue'.padStart(10, '_*')           //'_*_*_*_Vue'
'React'.padStart(10, 'Hello')      //'HelloReact'
'JavaScript'.padStart(10, 'Hi')    //'JavaScript'
'JavaScript'.padStart(8, 'Hi')     //'JavaScript'

 

從上面結果來看,填充函數只有在字元長度小於目標長度時才有效,若字元長度已經等於或小於目標長度時,填充字元不會起作用,而且目標長度如果小於字元串本身長度時,字元串也不會做截斷處理,只會原樣輸出。

padEnd函數作用同padStart,只不過它是從字元串尾部做填充。來看個小例子:

'Vue'.padEnd(10, '_*')           //'Vue_*_*_*_'
'React'.padEnd(10, 'Hello')      //'ReactHello'
'JavaScript'.padEnd(10, 'Hi')    //'JavaScript'
'JavaScript'.padEnd(8, 'Hi')     //'JavaScript'

 

Object.getOwnPropertyDescriptors()

顧名思義,該方法會返回目標對象中所有屬性的屬性描述符,該屬性必須是對象自己定義的,不能是從原型鏈繼承來的。先來看個它的基本用法:

let obj = {
  id: 1,
  name: 'test',
  get gender() {
    console.log('gender')
  },
  set grade(g) {
    console.log(g)
  }
}
Object.getOwnPropertyDescriptors(obj)

//輸出結果為:
{
  gender: {
    configurable: true,
    enumerable: true,
    get: f gender(),
    set: undefined
  },
  grade: {
    configurable: true,
    enumerable: true,
    get: undefined,
    set: f grade(g)
  },
  id: {
    configurable: true,
    enumerable: true,
    value: 1,
    writable: true
  },
  name: {
    configurable: true,
    enumerable: true,
    value: 'test',
    writable: true
  }
}

 

方法還提供了第二個參數,用來獲取指定屬性的屬性描述符。

let obj = {
  id: 1,
  name: 'test',
  get gender() {
    console.log('gender')
  },
  set grade(g) {
    console.log(g)
  }
}
Object.getOwnPropertyDescriptors(obj, 'id')

//輸出結果為:
{
  id: {
    configurable: true,
    enumerable: true,
    value: 1,
    writable: true
  }
}

 

由上述例子可知,該方法返回的描述符,會有兩種類型:數據描述符、存取器描述符。返回結果中包含的鍵可能的值有:configurable、enumerable、value、writable、get、set。

使用過Object.assign()的同學都知道,assign方法只能拷貝一個屬性的值,而不會拷貝它背後的複製方法和取值方法。Object.getOwnPropertyDescriptors()主要是為瞭解決Object.assign()無法正確拷貝get屬性和set屬性的問題。

let obj = {
  id: 1,
  name: 'test',
  get gender() {
    console.log('gender')
  }
}
Object.assign(obj)

//輸出結果為:
{
  gender: undefined
  id: 1,
  name: 'test'
}

 

此時,Object.getOwnPropertyDescriptors方法配合Object.defineProperties方法,就可以實現正確拷貝。

let obj = {
  id: 1,
  name: 'test',
  get gender() {
    console.log('gender')
  }
}
let obj1 = {}
Object.defineProperties(obj1, Object.getOwnPropertyDescriptors(obj))
Object.getOwnPropertyDescriptors(obj1)

//輸出結果為:
{
  gender: {
    configurable: true,
    enumerable: true,
    get: f gender(),
    set: undefined
  },
  id: {
    configurable: true,
    enumerable: true,
    value: 1,
    writable: true
  },
  name: {
    configurable: true,
    enumerable: true,
    value: 'test',
    writable: true
  }
}

 

上述代碼演示了,我們如何來拷貝一個屬性值為賦值方法或者取值方法的對象。更多Object.getOwnPropertyDescriptors的使用細則,可參見阮一峰的博客文章,鏈接奉上:http://es6.ruanyifeng.com/#docs/object#Object-getOwnPropertyDescriptors

共用記憶體和原子(Shared memory and atomics)

ES8引入了兩部分內容:新的構造函數SharedArrayBuffer、具有輔助函數的命名空間對象Atomics。共用記憶體允許多個線程併發讀寫數據,而原子操作則能夠進行併發控制,確保多個存在競爭關係的線程順序執行。

共用記憶體和原子也稱為共用陣列緩衝區,它是更高級的併發抽象的基本構建塊。它允許在多個工作者和主線程之間共用SharedArrayBuffer對象的位元組(緩衝區是共用的,用以訪問位元組,將其包裝在類型化的數組中)。這種共用有兩個好處:

  • 可以更快地在web worker之間共用數據
  • web worker之間的協調變得更加簡單和快速

那麼,我們為什麼要引入共用記憶體和原子的概念呢?以及SharedArrayBuffer的競爭條件是什麼,Atomics又是如何解決這種競爭的?推薦下麵的文章,文章講解很詳細,圖文並茂,帶你深入瞭解SharedArrayBufferAtomics

記憶體管理碰撞課程:https://segmentfault.com/a/1190000009878588

圖解 ArrayBuffers 和 SharedArrayBuffers:https://segmentfault.com/a/1190000009878632

用 Atomics 避免 SharedArrayBuffers 競爭條件:https://segmentfault.com/a/1190000009878699

Atomics對象提供了許多靜態方法,配合SharedArrayBuffer對象一起使用,可以幫助我們去構建一個記憶體共用的多線程編程環境。Atomic操作安裝在Atomics模塊上。與其他全局對象不同,Atomics不是構造函數。您不能使用new操作符或Atomics作為函數調用該對象。所有的屬性和方法Atomics都是靜態的,這一點跟Math類似。下麵鏈接貼出了Atomics提供的一些基本方法:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Atomics

關於共用記憶體和原子的深入研究,也可以參考Axel Rauschmayer博士的《Exploring ES2016 and ES2017》一書中的內容。具體章節鏈接如下:

http://exploringjs.com/es2016-es2017/ch_shared-array-buffer.html

函數參數列表與調用中的尾部逗號

該特性允許我們在定義或者調用函數時添加尾部逗號而不報錯。

let foo = function (
  a,
  b,
  c,
) {
  console.log('a:', a)
  console.log('b:', b)
  console.log('c:', c)
}
foo(1, 3, 4, )

//輸出結果為:
a: 1
b: 3
c: 4

 

上面這種方式調用是沒有問題的。函數的這種尾逗號也是向數組和字面量對象中尾逗號看齊,它適用於那種多行參數並且參數名很長的情況,開發過程中,如果忘記刪除尾部逗號也沒關係,ES8已經支持這種寫法。

這麼用有什麼好處呢?

首先,當我們調整結構時,不會因為最後一行代碼的位置變動,而去添加或者刪除逗號。

其次,在版本管理上,不會出現因為一個逗號,而使本來只有一行的修改,變成兩行。例如下麵:

從

(
  'abc'
)
到

(
  'abc',
  'def'
)

 

在我們版本管理系統里,它會監測到你有兩處更改,但是如果我們不必去關心逗號的存在,每一行都有逗號時,新加一行,也只會監測到一行的修改。

建議的ES9功能

回想一下,每個ECMAScript功能提案都經過了幾個階段:

  • 階段4意味著功能將在下一個版本中(或之後的版本)。
  • 階段3意味著功能仍然有機會被包含在下一個版本中。
第4階段和部分ECMAScript規範草案

以下功能目前在第4階段:

  • Template Literal Revision:模板文字修訂(蒂姆·迪士尼)
候選功能(第3階段)

以下功能目前在第3階段:

  • Function.prototype.toString 修訂版(Michael Ficarra)
  • global(Jordan Harband)
  • Rest/Spread Properties:Rest/Spread屬性(SebastianMarkbåge)
  • Asynchronous Iteration:非同步迭代(Domenic Denicola)
  • import() (Domenic Denicola)
  • RegExp Lookbehind Assertions:RegExp Lookbehind斷言(Daniel Ehrenberg)
  • RegExp Unicode Property Escapes:RegExp Unicode屬性轉義(Brian Terlson,Daniel Ehrenberg,Mathias Bynens)
  • RegExp named capture groups:RegExp命名捕獲組(Daniel Ehrenberg,Brian Terlson)
  • s (dotAll) flag for regular expressions:s(dotAll)標誌為正則表達式(Mathias Bynens,Brian Terlson)
  • Promise.prototype.finally() (Jordan Harband)
  • BigInt - 任意精度整數(Daniel Ehrenberg)
  • Class fields(Daniel Ehrenberg,Jeff Morrison)
  • Optional catch binding(Michael Ficarra)

下麵貼出瞭解和學習ES的官方鏈接,供大家查閱:

 

 

如果你喜歡我們的文章,關註我們的公眾號和我們互動吧。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 用途 遍歷一個jQuery對象,為每個匹配的元素執行一個函數。 語法 .each(function) 參數 function:類型為Function(Integer index,Element element),每個匹配的元素要執行的函數 可以通過讓回調函數返回false來終止迭代。 返回值 返回調 ...
  • 用途 jQuery.trim()函數用於刪除指定字元串開頭和結尾的空格。 $.trim()函數將刪除指定字元串開頭和結尾的所有的換行符、空格,以及製表符。 語法 jQuery.trim(str) 參數 str:要去除前後空格的字元串 返回值 jQuery.trim()方法返回去除了前後空格的字元串 ...
  • substring 方法用於提取字元串中介於兩個指定下標之間的字元 substring(start,end) 開始和結束的位置,從零開始的索引 返回值是一個新的字元串,該字元串值包含 stringObject 的一個子字元串 substring 方法返回的子串包括 start 處的字元,但不包括 e ...
  • 1.DOM內部插入append()與appendTo() 動態創建的元素是不夠的,它只是臨時存放在記憶體中,最終我們需要放到頁面文檔並呈現出來。那麼問題來了,怎麼放到文檔上? 這裡就涉及到一個位置關係,常見的就是把這個新創建的元素,當作頁面某一個元素的子元素放到其內部。針對這樣的處理,jQuery就定 ...
  • 近日壓力山大,找找樂子,看有沒有好的東西可以研究研究,剛好看到我的螞蟻森林居然可以種樹了,很好奇,難道馬雲真會種樹? 二話不說,利用本人專業所學(遙感專業,有木有同行??),來監測監測那些樹木長得如何了?是不是真有,二話不說,直接上圖!! 註意,這裡是螞蟻森林種植的大概範圍,我從高德地圖查詢到的,內 ...
  • [1]坐標定位 [2]四個坐標系 [3]圖形變換 [4]居中變換 ...
  • 說到原生瀏覽器事件函數處理相容,大家可能會想到addEventListener().....以及attachEvent()....相信看了下文,會給你提供不一樣的更優雅的實現方式,希望下文會對你有幫助~~~~~ 總結:以上方法也是jquery源碼中Event模塊中add的方法的借鑒來源,資料來源於此 ...
  • 創建畫布,驗證瀏覽器相容性我就省去了,也很簡單網上有代碼。 然就是蛇對象 食物 移動 控制方向 吃到食物 吃到自己 基本功能大概就是這樣。可能還不算完美,後面有時間繼續優化一下! ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...