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

資訊專欄INFORMATION COLUMN

魔幻語言 JavaScript 系列之類型轉(zhuǎn)換、寬松相等以及原始值

li21 / 1624人閱讀

摘要:通過使用其構(gòu)造函數(shù),可以將一個值的類型轉(zhuǎn)換為另一種類型。如果使用兩次,可用于將該值轉(zhuǎn)換為相應(yīng)的布爾值。

編譯自:[1] + [2] – [3] === 9!? Looking into assembly code of coercion.

全文從兩個題目來介紹類型轉(zhuǎn)換、寬松相等以及原始值的概念:

[1] + [2] – [3] === 9

如果讓 a == true && a == false 的值為 true

第二道題目是譯者加的,因為這其實是個很好的例子,體現(xiàn)出 JavaScript 的魔幻之處

變量值都具有類型,但仍然可以將一種類型的值賦值給另一種類型,如果是由開發(fā)者進行這些操作,就是類型轉(zhuǎn)換(顯式轉(zhuǎn)換)。如果是發(fā)生在后臺,比如在嘗試對不一致的類型執(zhí)行操作時,就是隱式轉(zhuǎn)換(強制轉(zhuǎn)換)。

類型轉(zhuǎn)換(Type casting) 基本包裝類型(Primitive types wrappers)

在 JavaScript 中除了 nullundefined 之外的所有基本類型都有一個對應(yīng)的基本包裝類型。通過使用其構(gòu)造函數(shù),可以將一個值的類型轉(zhuǎn)換為另一種類型。

String(123); // "123"
Boolean(123); // true
Number("123"); // 123
Number(true); // 1
基本類型的包裝器不會保存很長時間,一旦完成相應(yīng)工作,就會消失

需要注意的是,如果在構(gòu)造函數(shù)前使用 new 關(guān)鍵字,結(jié)果就完全不同,比如下面的例子:

const bool = new Boolean(false);
bool.propertyName = "propertyValue";
bool.valueOf(); // false

if (bool) {
  console.log(bool.propertyName); // "propertyValue"
}

由于 bool 在這里是一個新的對象,已經(jīng)不再是基本類型值,它的計算結(jié)果為 true。

上述例子,因為在 if 語句中,括號間的表達式將會裝換成布爾值,比如

if (1) {
    console.log(true);
}

其實,上面這段代碼跟下面一樣:

if ( Boolean(1) ) {
    console.log(true);
}
parseFloat

parseFloat 函數(shù)的功能跟 Number 構(gòu)造函數(shù)類似,但對于傳參并沒有那么嚴格。當它遇到不能轉(zhuǎn)換成數(shù)字的字符,將返回一個到該點的值并忽略其余字符。

Number("123a45"); // NaN
parseFloat("123a45"); // 123
parseInt

parseInt 函數(shù)在解析時將會對數(shù)字進行向下取整,并且可以使用不同的進制。

parseInt("1111", 2); // 15
parseInt("0xF"); // 15
 
parseFloat("0xF"); // 0

parseInt 函數(shù)可以猜測進制,或著你可以顯式地通過第二個參數(shù)傳入進制,參考 MDN web docs。

而且不能正常處理大數(shù),所以不應(yīng)該成為 Math.floor 的替代品,是的,Math.floor 也會進行類型轉(zhuǎn)換:

parseInt("1.261e7"); // 1
Number("1.261e7"); // 12610000
Math.floor("1.261e7") // 12610000
 
Math.floor(true) // 1
toString

可以使用 toString 函數(shù)將值轉(zhuǎn)換為字符串,但是在不同原型之間的實現(xiàn)有所不同。

String.prototype.toString

返回字符串的值

const dogName = "Fluffy";
 
dogName.toString() // "Fluffy"
String.prototype.toString.call("Fluffy") // "Fluffy"
 
String.prototype.toString.call({}) // Uncaught TypeError: String.prototype.toString requires that "this" be a String

Number.prototype.toString

返回將數(shù)字的字符串表示形式,可以指定進制作為第一個參數(shù)傳入

(15).toString(); // "15"
(15).toString(2); // "1111"
(-15).toString(2); // "-1111"

Symbol .prototype.toString

返回 Symbol(${description})

Boolean.prototype.toString

返回 “true”“false”

Object.prototype.toString

返回一個字符串 [ object $ { tag } ] ,其中 tag 可以是內(nèi)置類型比如 “Array”,“String”,“Object”,“Date”,也可以是自定義 tag。

const dogName = "Fluffy";
 
dogName.toString(); // "Fluffy" (String.prototype.toString called here)
Object.prototype.toString.call(dogName); // "[object String]"

隨著 ES6 的推出,還可以使用 Symbol 進行自定義 tag。

const dog = { name: "Fluffy" }
console.log( dog.toString() ) // "[object Object]"
 
dog[Symbol.toStringTag] = "Dog";
console.log( dog.toString() ) // "[object Dog]"

或者

const Dog = function(name) {
  this.name = name;
}
Dog.prototype[Symbol.toStringTag] = "Dog";
 
const dog = new Dog("Fluffy");
dog.toString(); // "[object Dog]"

還可以結(jié)合使用 ES6 class 和 getter:

class Dog {
  constructor(name) {
    this.name = name;
  }
  get [Symbol.toStringTag]() {
    return "Dog";
  }
}
 
const dog = new Dog("Fluffy");
dog.toString(); // "[object Dog]"

Array.prototype.toString

在每個元素上調(diào)用 toString,并返回一個字符串,并且以逗號分隔。

const arr = [
  {},
  2,
  3
]
 
arr.toString() // "[object Object],2,3"
強制轉(zhuǎn)換

如果了解類型轉(zhuǎn)換的工作原理,那么理解強制轉(zhuǎn)換就會容易很多。

數(shù)學(xué)運算符

加號運算符

在作為二元運算符的 + 如果兩邊的表達式存在字符串,最后將會返回一個字符串。

"2" + 2 // "22"
15 + "" // "15"

可以使用一元運算符將其轉(zhuǎn)換為數(shù)字:

+"12" // 12

其他數(shù)學(xué)運算符

其他數(shù)學(xué)運算符(如 -/)將始終轉(zhuǎn)換為數(shù)字。

new Date("04-02-2018") - "1" // 1522619999999
"12" / "6" // 2
-"1" // -1

上述例子中,Date 類型將轉(zhuǎn)換為數(shù)字,即 Unix 時間戳。

邏輯非

如果原始值是 ,則使用邏輯非將輸出 ,如果 ,則輸出為 。 如果使用兩次,可用于將該值轉(zhuǎn)換為相應(yīng)的布爾值。

!1 // false
!!({}) // true
位或

值得一提的是,即使 ToInt32 實際上是一個抽象操作(僅限內(nèi)部,不可調(diào)用),將一個值轉(zhuǎn)換為一個有符號的 32 位整數(shù)。

0 | true          // 1
0 | "123"         // 123
0 | "2147483647"  // 2147483647
0 | "2147483648"  // -2147483648 (too big)
0 | "-2147483648" // -2147483648
0 | "-2147483649" // 2147483647 (too small)
0 | Infinity      // 0

當其中一個操作數(shù)為 0 時執(zhí)行按位或操作將不改變另一個操作數(shù)的值。

其他情況下的強制轉(zhuǎn)換

在編碼時,可能會遇到更多強制轉(zhuǎn)換的情況,比如這個例子:

const foo = {};
const bar = {};
const x = {};
 
x[foo] = "foo";
x[bar] = "bar";
 
console.log(x[foo]); // "bar"

發(fā)生這種情況是因為 foobar 在轉(zhuǎn)換為字符串的結(jié)果均為 “[object Object]”。就像這樣:

x[bar.toString()] = "bar";
x["[object Object]"]; // "bar"

使用模板字符串的時候也會發(fā)生強制轉(zhuǎn)換,在下面例子中重寫 toString 函數(shù):

const Dog = function(name) {
  this.name = name;
}
Dog.prototype.toString = function() {
  return this.name;
}
 
const dog = new Dog("Fluffy");
console.log(`${dog} is a good dog!`); // "Fluffy is a good dog!"

正因為如此,寬松相等(==)被認為是一種不好的做法,如果兩邊類型不一致,就會試圖進行強制隱式轉(zhuǎn)換。

看下面這個有趣的例子:

const foo = new String("foo");
const foo2 = new String("foo");
 
foo === foo2 // false
foo >= foo2 // true

在這里我們使用了 new 關(guān)鍵字,所以 foofoo2 都是字符串包裝類型,原始值都是 foo 。但是,它們現(xiàn)在引用了兩個不同的對象,所以 foo === foo2 將返回 false。這里的關(guān)系運算符 >= 會在兩個操作數(shù)上調(diào)用 valueOf 函數(shù),因此比較的是它們的原始值,"foo" > = "foo" 的結(jié)果為 true。

[1] + [2] - [3] === 9

希望這些知識都能幫助揭開這個題目的神秘面紗

[1] + [2] 將調(diào)用 Array.prototype.toString 轉(zhuǎn)換為字符串,然后進行字符串拼接。結(jié)果將是 “12”

[1,2] + [3,4] 的值講師 “1,23,4”

12 - [3],減號運算符會將值轉(zhuǎn)換為 Number 類型,所以等于 12-3,結(jié)果為 9

12 - [3,4] 的值是 NaN,因為"3,4" 不能被轉(zhuǎn)換為 Number

總結(jié)

盡管很多人會建議盡量避免強制隱式轉(zhuǎn)換,但了解它的工作原理非常重要,在調(diào)試代碼和避免錯誤方面大有幫助。

【譯文完】

再談點,關(guān)于寬松相等和原始值

這里看另一道題目,在 JavaScript 環(huán)境下,能否讓表達式 a == true && a == falsetrue。

就像下面這樣,在控制臺打印出 ’yeah":

// code here
if (a == true && a == false) {
    console.log("yeah");
}

關(guān)于寬松相等(==),先看看 ECMA 5.1 的規(guī)范,包含 toPrimitive:

11.9.3 The Abstract Equality Comparison Algorithm

9.1 ToPrimitive

稍作總結(jié)

規(guī)范很長很詳細,簡單總結(jié)就是,對于下述表達式:

x == y

類型相同,判斷的就是 x === y

類型不同

如果 x,y 其中一個是布爾值,將這個布爾值進行 ToNumber 操作

如果 x,y 其中一個是字符串,將這個字符串進行 ToNumber 操作

若果 x,y 一方為對象,將這個對象進行 ToPrimitive 操作

至于 ToPrimitive,即求原始值,可以簡單理解為進行 valueOf()toString() 操作。

稍后我們再詳細剖析,接下來先看一個問題。

Question:是否存在這樣一個變量,滿足 x == !x

就像這樣:

// code here
if (x == !x) {
    console.log("yeah");
}

可能很多人會想到下面這個,畢竟我們也曾熱衷于各種奇技淫巧:

[] == ![] // true

但答案絕不僅僅局限于此,比如:

var x = new Boolean(false);

if (x == !x) {
    console.log("yeah");
}
// x.valueOf() -> false
// x is a object, so: !x -> false


var y = new Number(0);
y == !y // true
// y.valueOf() -> 0
// !y -> false
// 0 === Number(false) // true
// 0 == false // true

理解這個問題,那下面的這些例子都不是問題了:

[] == ![]
[] == {}
[] == !{}
{} == ![]
{} == !{}

在來看看什么是 ToPrimitive

ToPrimitive

看規(guī)范:8.12.8 [[DefaultValue]] (hint)

如果是 Date 求原始值,則 hint 是 String,其他均為 Number,即先調(diào)用 valueOf() 再調(diào)用 toString()。

如果 hint 為 Number,具體過程如下:

調(diào)用對象的 valueOf() 方法,如果值是原值則返回

否則,調(diào)用對象的 toString() 方法,如果值是原值則返回

否則,拋出 TypeError 錯誤

// valueOf 和 toString 的調(diào)用順序
var a = {
    valueOf() {
        console.log("valueof")
        return []
    },
    toString() {
        console.log("toString")
        return {}
    }
}

a == 0
// valueof
// toString
// Uncaught TypeError: Cannot convert object to primitive value


// Date 類型先 toString,后 valueOf
var t = new Date("2018/04/01");
t.valueOf = function() {
    console.log("valueof")
    return []
}
t.toString = function() {
    console.log("toString")
    return {}
}
t == 0
// toString
// valueof
// Uncaught TypeError: Cannot convert object to primitive value

到目前為止,上面的都是 ES5 的規(guī)范,那么在 ES6 中,有什么變化呢

ES6 中 ToPrimitive

7.1.1ToPrimitive ( input [, PreferredType] )

在 ES6 中嗎,是可以自定義 @@toPrimitive 方法的,這是 Well-Known Symbols(§6.1.5.1)中的一個。JavaScript 內(nèi)建了一些在 ECMAScript 5 之前沒有暴露給開發(fā)者的 symbol,它們代表了內(nèi)部語言行為。

來自 MDN 的例子:

// 沒有 Symbol.toPrimitive 屬性的對象
var obj1 = {};
console.log(+obj1); // NaN
console.log(`${obj1}`); // "[object Object]"
console.log(obj1 + ""); // "[object Object]"

// 擁有 Symbol.toPrimitive 屬性的對象
var obj2 = {
    [Symbol.toPrimitive](hint) {
        if (hint == "number") {
            return 10;
        }
        if (hint == "string") {
            return "hello";
        }
        return true;
    }
};
console.log(+obj2); // 10 -- hint is "number"
console.log(`${obj2}`); // "hello" -- hint is "string"
console.log(obj2 + ""); // "true" -- hint is "default"

有了上述鋪墊,答案就呼之欲出了

a == true && a == falsetrue 的答案
var a = {
    flag: false,
    toString() {
        return this.flag = !this.flag;
    }
}

或者使用 valueOf()

var a = {
    flag: false,
    valueOf() {
        return this.flag = !this.flag;
    }
}

或者是直接改變 ToPrimitive 行為:

// 其實只需設(shè)置 default 即可
var a = {
    flag: false,
    [Symbol.toPrimitive](hint) {
        if (hint === "number") {
            return 10
        }
        if (hint === "string") {
            return "hello"
        }
        return this.flag = !this.flag
    }
}
如果是嚴格相等呢

這個問題在嚴格相等的情況下,也是能夠成立的,這又是另外的知識點了,使用 defineProperty 就能實現(xiàn):

let flag = false
Object.defineProperty(window, "a", {
    get() {
        return (flag = !flag)
    }
})

if (a === true && a === false) {
    console.log("yeah");
}
閱讀更多

Can (a== 1 && a ==2 && a==3) ever evaluate to true?

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/94166.html

相關(guān)文章

  • 魔幻語言 JavaScript 系列 a == true && a == fals

    摘要:稍后我們再詳細剖析,接下來先看一個問題。還內(nèi)建了一些在之前沒有暴露給開發(fā)者的,它們代表了內(nèi)部語言行為。使用,可能有不少朋友一開始就想到這種方式,簡單貼一下閱讀更多 在 JavaScript 環(huán)境下,可以讓表達式 a == true && a == false 為 true 嗎? 就像下面這樣,可以在控制臺打印出 ’yeah: // code here if (a == true && ...

    BDEEFE 評論0 收藏0
  • 魔幻語言 JavaScript 系列 call、bind 以及上下文

    摘要:那么,它到底是如何工作的呢讓我們從一種更簡單的實現(xiàn)開始實際上這種實現(xiàn)代碼更短,并且更易讀是函數(shù)原型中的一個函數(shù),它調(diào)用函數(shù),使用第一個參數(shù)作為參數(shù),并傳遞剩余參數(shù)作為被調(diào)用函數(shù)的參數(shù)。 原文:The Most Clever Line of JavaScript 作者:Seva Zaikov 原文 最近 一個朋友 發(fā)給我一段非常有趣的 JavaScript 代碼,是他在某個 開源庫中...

    cuieney 評論0 收藏0
  • JavaScript疑難雜癥系列-相等性判斷

    摘要:同一類的復(fù)合類型值兩個復(fù)合類型對象數(shù)組函數(shù)的數(shù)據(jù)比較時,不是比較它們的值是否相等,而是比較它們是否指向同一個對象。寬松相等雙等號將執(zhí)行類型轉(zhuǎn)換原始類型的值原始類型的數(shù)據(jù)會轉(zhuǎn)換成數(shù)值類型再進行比較。 事件這塊知識點雖然是老生長談的,但對于我來說多多整理,多多感悟,溫故知新,每次看看這塊都有不同的收獲.(在這里我不會長篇大論,只會挑重點;具體的小伙伴們自行查找)參考:https://dev...

    Flink_China 評論0 收藏0
  • JavaScript疑難雜癥系列-相等性判斷

    摘要:同一類的復(fù)合類型值兩個復(fù)合類型對象數(shù)組函數(shù)的數(shù)據(jù)比較時,不是比較它們的值是否相等,而是比較它們是否指向同一個對象。寬松相等雙等號將執(zhí)行類型轉(zhuǎn)換原始類型的值原始類型的數(shù)據(jù)會轉(zhuǎn)換成數(shù)值類型再進行比較。 事件這塊知識點雖然是老生長談的,但對于我來說多多整理,多多感悟,溫故知新,每次看看這塊都有不同的收獲.(在這里我不會長篇大論,只會挑重點;具體的小伙伴們自行查找)參考:https://dev...

    2bdenny 評論0 收藏0

發(fā)表評論

0條評論

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