国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

ES6新語法疑點簡析

silencezwm / 2601人閱讀

摘要:本文涵蓋了一些新語法可能造成疑惑的地方和一些建議。新接口的迭代器參數的誤調用接口及集合類構造器的參數,可以放入支持迭代器的內容,而不局限于數組兼容。新集合類容器的構造器集合類容器不可以通過非方式來構造。

本文涵蓋了一些ES6新語法可能造成疑惑的地方和一些建議。

1# 箭頭函數

箭頭函數看起來像是匿名函數表達式function(){}的簡寫,然而它不是。

這個例子應該很容易看出來會有怎樣的問題:

function Apple(){}

Apple.prototype.check = ()=>{
    console.log(this instanceof Apple);
};

(new Apple()).check() // false

使用apply、call、bind改變箭頭函數的this指向呢?

var i = 0;
var xx = ()=>{ console.log(++i, this) };
var yy = function(){ console.log(++i, this) };

xx();             // 1 window
xx.apply([]);     // 2 window
xx.bind([])();    // 3 window
yy();             // 4 window
yy.apply([]);     // 5 []
yy.bind([])();    // 6 []

顯然apply、call、bind無法改變箭頭函數的this指向,箭頭函數的this確定后無法更改。

在這些場景中不要使用箭頭函數:

當你需要正常使用this binding時,如函數構造器、prototype

當你需要動態改變this的時候

針對工作報酬和代碼量呈反比的程序猿,在需要用到this binding的場景里,可能比較適合的簡寫形式是在新對象字面量語法里提供的:

var obj = {
    hello() { // 少寫了一個function耶!
        console.log("world")
    } 
};
2# Promise 2.1# then
//1
fetch(xx, oo).then(handleResultAndReturnsAnPromise(result));
//2 
fetch(xx, oo).then(handleResultAndReturnsAnPromise);
//3 
fetch(xx, oo).then((result) => handleResultAndReturnsAnPromise(result));
//4
fetch(xx, oo).then(function(result) { handleResultAndReturnsAnPromise(result) });

1與2、3、4均不等價:1同步調用了handleResultAndReturnsAnPromise;而2~4均會導致handleResultAndReturnsAnPromise在fetch之后完成

2與3/4則是運行時的調用棧有區別,3/4額外創建了一個匿名函數。

3與4除了this binding的區別,4的調用返回值沒有進行返回,這樣將導致promise鏈斷裂。

1中需要注意的是,then(promise)里面傳一個 Promise 對象是沒有什么意義的,它會被當成then(null),在下面推薦的文章中,它被稱作“Promise 穿透”

更多的令人混淆的案例,請繼續閱讀《談談使用 promise 時候的一些反模式》。

2.2# catch

在node的一些版本中,采用Promise并忘記給promise鏈增加catch(fn)then(null, fn),將導致代碼中的異常被吞掉。

這個問題在新的v8中(node 6.6+,chrome最新版)會導致一個UnhandledPromiseRejectionWarning,防止開發遺漏。

node -e "Promise.reject()"
# UnhandledPromiseRejectionWarning: Unhandled promise rejection
2.3# resolve

Promise接口和jQuery實現的接口不一樣,resolve只接受單參數,then的回調也只能拿到單參數。

在Promise規范中的單參數鏈式調用場景下,可以利用解構、_.spread、訪問自由變量等方式來處理多個過程中得到的值:

new Promise(function(resolve, reject){
    let something = 1,
        otherstuff = 2;
    resolve({something, otherstuff});
}).then(function({something, otherstuff}){
    // handle something and otherstuff
});
Promise.all([
    Promise.resolve(40), Promise.resolve(36)
]).then(
    _.spread(function(first, second){
        // first: 40, second: 36
    })
);
let someMiddleResult;
fetch()
    .then(function(fetchResult){
        someMiddleResult = fetchResult;
    })
    .then(otherHandleFn)
    .then(function(otherHandleFnResult){
        // use both someMiddleResult and otherHandleFnResult now
    })
2.4# reject / throw

出現reject接口,應該是第一次前端有機會拿異常處理流程做正常流程(比如*)。不要這樣做。

由于reject(new Error(""))throw new Error("")都能作為catch的入口,一些不可預知的錯誤被拋出的時候,這樣的處理方式將會復雜化catch內的代碼。不要用異常處理邏輯來做正常處理流程,這個規則保證了代碼可讀性與可維護性。

throwreject都可以作為catch的入口,它們更加詳細的區別如下:

new Promise((resolve, reject) => {
    setTimeout(function(){
        reject(new Error("hello"));
    });
}).catch(() => console.log("reject"));
// reject

new Promise((resolve, reject) => {
    setTimeout(function(){
        throw new Error("hello");
    });
}).catch(() => console.log("throw"));
// Uncaught Error: hello

reject能夠“穿透”回調;而throw限于函數作用域,無法“穿透”回調。

建議:

正常流程請選擇在then的時候if..else,不要用reject替代

在需要走異常處理流程的時候封裝Error拋出,可以最大化的化簡catch回調里面的處理邏輯,類似于e instanceof MyDesignedError

由于回調函數里的throw無法被自動捕獲到,如果需要在回調中reject當前 promise,那么我們需要用reject而不是throw

在使用Promise接口的 polyfill 的場景,應當在reject后加一個return

3# let & const & var

看起來letconst的組合就像是一個能完全滅掉var的新特性,但對舊代碼不能簡單的正則替換掉var,因為我們太習慣于濫用它的特性了——主要是聲明提升。

一些情形下會造成語法錯誤:

try {
    let a = 10;

    if (a > 2) {
        throw new Error();
    }

    // ...
} catch (err) {
    console.log(a);
    // 若為var聲明,不報錯
    // 若為const、let聲明:Uncaught ReferenceError: a is not defined
}

除了try..catch,隱式造就的塊級作用域在forif..else中也將造成問題:

if(false) {
    let my = "bad";
} else {
    console.log(my); // ReferenceError: my is not defined
}

解決方案倒是很簡單,將作用域內的let放在更靠外層的位置即可。

varletconst的區別如下(部分參考自stackoverflow*):

作用域:letconst將創造一個塊級作用域,在作用域之外此變量不可見,作用域外訪問將導致SyntaxErrorvar遵循函數級作用域

全局影響:全局作用域下的var使用等同于設置window/global之上的內容,但letconst不會

提升行為:var聲明有提升到當前函數作用域頂部的特性,但constlet沒有,在聲明前訪問變量將導致SyntaxError

重新賦值:對const變量所做的重新賦值將導致TypeError,而varlet不會

重新聲明:var聲明的變量使用var再次聲明不會出現SyntaxError,但constlet聲明的變量不能被重新聲明,也不能覆蓋掉之前任何形式的聲明:

var vVar = 1;
const vConst = 2;
let vLet = 3;

var vVar = 4;     // success
let vVar = 5;     // SyntaxError
const vVar = 6;   // SyntaxError

var vConst = 7;   // SyntaxError
let vConst = 8;   // SyntaxError
const vConst = 9; // SyntaxError

var vLet = 10;    // SyntaxError
let vLet = 11;    // SyntaxError
const vLet = 12;  // SyntaxError
4# 邊界

本篇章集結 ES6 給予的不同邊界條件,部分編譯自 You don"t know JS

4.1# 函數默認參數值
function before(a) { var a = a || 1; console.log(a); }
function after(a = 1) { console.log(a); }

before(NaN) // 1
after(NaN) // NaN

新的寫法的fallback邏輯只針對undefined有效。

4.2# Object.assign

Object.assign將賦予所有的可枚舉值,但不包含從原型鏈繼承來的值:

let arr = [1, 2, 3],
    obj = {};
Object.assign(obj, arr);

obj[1] // 2
obj.length // undefined
Object.getOwnPropertyDescriptors(arr).length.enumerable // false

此外:Object.assign僅僅進行淺拷貝:

var orig = {
    a: [1, 2, 3]
},
    nObj = {};

Object.assign(nObj, orig);
orig.a.push(4);
nObj.a // [1, 2, 3, 4]
4.3# NaN

Number.isNaN和全局空間中的isNaN的區別在于不存在隱式轉換:

isNaN("number") // true
Number.isNaN("number") // false

Object.is除了區分正負零這個非常小眾的邊界,這個接口相對===更大的意義是判斷NaN:

Object.is(NaN, NaN); // true
NaN === NaN; // false
Object.is(+0, -0); // false
+0 === -0; // true

同樣的,arr.includes(xx)arr.lastIndexOf(xx) > -1好的地方也包括對于NaN的處理:

[1, 2, NaN].includes(NaN); // true
4.4# Number

isFiniteNumber.isFinite的區別也是后者不存在隱式轉換:

isFinite("42");        // true
Number.isFinite("42"); // false

Number.isInteger表示一個數是不是小數,和x === Math.floor(x)的區別在于對Infinity的處理

Number.isInteger(Infinity);        // false
Infinity === Math.floor(Infinity); // true

Number.isSafeInteger表示傳入的數值有沒有精度損失,它比較的是數字是否在Number.MIN_SAFE_INTEGERNumber.MAX_SAFE_INTEGER之間:

Number.isSafeInteger(Math.pow(2, 53) - 1); // true
Number.isSafeInteger(Math.pow(2, 53)); // false

我曾整理過Number的數軸(*),也寫過JavaScript中的一些數字內存模型的demo,其中有一部分值沒有直接的量來表示,但現在有了。

從負無窮往正無窮來看,是這樣的:

Number.NEGATIVE_INFINITY 負無窮

-Number.MAX_VALUE 能表示的最小數字,更小被視為負無窮,等于-(2^53-1)*(2^971)

Number.MIN_SAFE_INTEGER(新) 沒有精度誤差的最小數,等于-(2^53-1)

0 正負零

Number.EPSILON(新) IEEE 754規范下的精度位允許的最小差異值,等于2^-52

Number.MIN_VALUE 能表示的最小正整數,這是一個IEEE 754規范下的反規格化值,等于2^-1074

Number.MAX_SAFE_INTEGER(新) 沒有精度誤差的最大數,,等于2^53-1

Number.MAX_VALUE 能表示的最大數字,更大被視為正無窮,等于(2^53-1)*(2^971)

Number.INFINITY 正無窮

比較令人混淆的是Number.EPSILONNumber.MIN_VALUE,前者為精度位允許的最小差異值,考慮的是浮點數的精度位;而后者考慮的是利用到浮點數的所有位置能夠表示的最小正數值。

5# 怪奇錯誤展

本節收集了一些奇奇怪怪的錯誤提示,正常寫出的代碼不會導致它們,沒有興趣可以略過。

5.1# 新接口的迭代器參數
Array.from(1, 2, 3) // Array.of(1,2,3)的誤調用
// 2 is not a function

Array.fromPromise.all接口及集合類構造器的參數,可以放入支持迭代器的內容,而不局限于數組(node 0.12+兼容)。這里其實嘗試去調用了參數的迭代器Symbol.iterator

5.2# 新集合類容器的構造器
Array(); // []
Set(); // Uncaught TypeError: Constructor Set requires "new"

集合類容器Int8Array Uint8Array Uint8ClampedArray Int16Array Uint16Array Int32Array Uint32Array Float32Array Float64Array Set不可以通過非new方式來構造。

5.3# Tagged Template
var x = 30
`abcdefg`
// Uncaught TypeError: 30 is not a function

模版語法可能是ES6最為顯然的語法,但它的擴展形式Tagged Template在極端場景可能造成一個奇怪的報錯,算是對不寫分號黨造成的又一個暴擊*。

6# 欺負新來的

本篇章集結一些被濫用的特性。

6.1

解構特性很棒,它可以在promise這樣的單參數鏈式調用場景或是正則匹配場景中大方光芒,更為經典的是python風格的[y, x] = [x, y]

但如果一個人鐵了心要瘋狂解構,新來維護這份代碼的人就要默默流下痛苦的眼淚了:

// 新人:是什么阻止了你用 a2 = [o1[a], o1[b], o1[c]] ……
var o1 = { a: 1, b: 2, c: 3 },
    a2 = [];

( { a: a2[0], b: a2[1], c: a2[2] } = o1 );
// 老人:看得爽嗎
var { a: { b: [ c, d ], e: { f } }, g } = obj;
// 主管:寫到一半這個程序猿已經被打死了
var x = 200, y = 300, z = 100;
var o1 = { x: { y: 42 }, z: { y: z } };

( { y: x = { y: y } } = o1 );
( { z: y = { y: z } } = o1 );
( { x: z = { y: x } } = o1 );

一個可以嘗試的保持代碼可讀性的方法,是盡量保證解構的層次低。

6.2

新對象字面量也很不錯,新的rest操作符也很實用,但是如果你們把它們混在一起……下面進一段代碼賞析(*):

export const sharePostStatus = createReducer( {}, {
    [ PUBLICIZE_SHARE ]: ( state, { siteId, postId } ) => ( { ...state, [ siteId ]: { ...state[ siteId ], [ postId ]: {
        requesting: true,
    } } } ),
    [ PUBLICIZE_SHARE_SUCCESS ]: ( state, { siteId, postId } ) => ( { ...state, [ siteId ]: { ...state[ siteId ], [ postId ]: {
        requesting: false,
        success: true,
    } } } ),
    [ PUBLICIZE_SHARE_FAILURE ]: ( state, { siteId, postId, error } ) => ( { ...state, [ siteId ]: { ...state[ siteId ], [ postId ]: {
        requesting: false,
        success: false,
        error,
    } } } ),
    [ PUBLICIZE_SHARE_DISMISS ]: ( state, { siteId, postId } ) => ( { ...state, [ siteId ]: {
        ...state[ siteId ], [ postId ]: undefined
    } } ),
} );

盡可能的保持代碼的可讀性,一行只用不超過2個ES6特性或許是一個可操作的方案。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/81332.html

相關文章

  • Loader學習,簡析babel-loader

    摘要:用來轉換內容,內部調用了方法進行轉換,這里簡單介紹一下的原理將代碼解析成,對進行轉譯,得到新的,新的通過轉換成,核心方法在中的方法,有興趣可以去了解一下。將函數傳入參數和歸并,得到。通常我們是用不上的,估計在某些中可能會使用到。 什么是Loader? 繼上兩篇文章webpack工作原理介紹(上篇、下篇),我們了解到Loader:模塊轉換器,也就是將模塊的內容按照需求裝換成新內容,而且每...

    wpw 評論0 收藏0
  • Immer.js簡析

    摘要:所以整個過程只涉及三個輸入狀態,中間狀態,輸出狀態關鍵是是如何生成,如何應用修改,如何生成最終的。至此基本把上的模式解析完畢。結束實現還是相當巧妙的,以后可以在狀態管理上使用一下。 開始 在函數式編程中,Immutable這個特性是相當重要的,但是在Javascript中很明顯是沒辦法從語言層面提供支持,但是還有其他庫(例如:Immutable.js)可以提供給開發者用上這樣的特性,所...

    Aceyclee 評論0 收藏0
  • Immer.js簡析

    摘要:所以整個過程只涉及三個輸入狀態,中間狀態,輸出狀態關鍵是是如何生成,如何應用修改,如何生成最終的。至此基本把上的模式解析完畢。結束實現還是相當巧妙的,以后可以在狀態管理上使用一下。 開始 在函數式編程中,Immutable這個特性是相當重要的,但是在Javascript中很明顯是沒辦法從語言層面提供支持,但是還有其他庫(例如:Immutable.js)可以提供給開發者用上這樣的特性,所...

    dackel 評論0 收藏0
  • 前端計劃——JavaScript正則表達式快速入門

    摘要:前言正則表達式時處理字符串中常用的手法,本文以簡單的方式,快速展示了中正則相關的基礎知識點。文末還提供了幾個簡單的正則相關面試題。接下來是正則部分,注意后面的并不匹配,也就是比如,實際匹配的值是和,在和后面加上,就完成了預期。 前言:正則表達式時處理字符串中常用的手法,本文以簡單的方式,快速展示了JavaScript中正則相關的基礎知識點。文末還提供了幾個簡單的正則相關面試題。個人總結...

    Xufc 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<