日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢(xún)
選擇下列產(chǎn)品馬上在線(xiàn)溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
全面分析toString與valueOf,并隨手解決掉幾道大廠必備面試題

基本上,所有JS數(shù)據(jù)類(lèi)型都擁有這兩個(gè)方法,null除外。它們倆是位于原型鏈上的方法,也是為了解決javascript值運(yùn)算與顯示的問(wèn)題。

創(chuàng)新互聯(lián)堅(jiān)持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:成都做網(wǎng)站、成都網(wǎng)站制作、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿(mǎn)足客戶(hù)于互聯(lián)網(wǎng)時(shí)代的昌平網(wǎng)站設(shè)計(jì)、移動(dòng)媒體設(shè)計(jì)的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!

valueOf 和 toString 幾乎都是在出現(xiàn)操作符(+-*/==><)時(shí)被調(diào)用(隱式轉(zhuǎn)換)。

toString

返回一個(gè)表示該對(duì)象的字符串,當(dāng)對(duì)象表示為文本值或以期望的字符串方式被引用時(shí),toString方法被自動(dòng)調(diào)用。

1. 手動(dòng)調(diào)用看看什么效果

嗯,跟介紹的一樣,沒(méi)騙人,全部都轉(zhuǎn)成了字符串。

比較特殊的地方就是,表示對(duì)象的時(shí)候,變成[object Object],表示數(shù)組的時(shí)候,就變成數(shù)組內(nèi)容以逗號(hào)連接的字符串,相當(dāng)于Array.join(',')。

 
 
 
  1. let a = {} 
  2. let b = [1, 2, 3] 
  3. let c = '123' 
  4. let d = function(){ console.log('fn') }
  5. console.log(a.toString())   // '[object Object]' 
  6. console.log(b.toString())   // '1,2,3' 
  7. console.log(c.toString())   // '123' 
  8. console.log(d.toString())   // 'function(){ console.log('fn') }'

2. 最精準(zhǔn)的類(lèi)型判斷

這種屬于更精確的判斷方式,在某種場(chǎng)合會(huì)比使用 typeof & instanceof 來(lái)的更高效和準(zhǔn)確些。

 
 
 
  1. toString.call(()=>{})       // [object Function] 
  2. toString.call({})           // [object Object] 
  3. toString.call([])           // [object Array] 
  4. toString.call('')           // [object String] 
  5. toString.call(22)           // [object Number] 
  6. toString.call(undefined)    // [object undefined] 
  7. toString.call(null)         // [object null] 
  8. toString.call(new Date)     // [object Date] 
  9. toString.call(Math)         // [object Math] 
  10. toString.call(window)       // [object Window]

3. 什么時(shí)候會(huì)自動(dòng)調(diào)用呢

使用操作符的時(shí)候,如果其中一邊為對(duì)象,則會(huì)先調(diào)用toSting方法,也就是隱式轉(zhuǎn)換,然后再進(jìn)行操作。

 
 
 
  1. let c = [1, 2, 3] 
  2. let d = {a:2} 
  3. Object.prototype.toString = function(){ 
  4.     console.log('Object') 
  5. Array.prototype.toString = function(){ 
  6.     console.log('Array') 
  7.     return this.join(',')   // 返回toString的默認(rèn)值(下面測(cè)試) 
  8. Number.prototype.toString = function(){ 
  9.     console.log('Number') 
  10. String.prototype.toString = function(){ 
  11.     console.log('String') 
  12. console.log(2 + 1)  // 3 
  13. console.log('s')    // 's' 
  14. console.log('s'+2)  // 's2' 
  15. console.log(c < 2)  // false        (一次 => 'Array') 
  16. console.log(c + c)  // "1,2,31,2,3" (兩次 => 'Array') 
  17. console.log(d > d)  // false        (兩次 => 'Object')

4. 重寫(xiě)toString方法

既然知道了有 toString 這個(gè)默認(rèn)方法,那我們也可以來(lái)重寫(xiě)這個(gè)方法

 
 
 
  1. class A { 
  2.     constructor(count) { 
  3.         this.count = count 
  4.     } 
  5.     toString() { 
  6.         return '我有這么多錢(qián):' + this.count 
  7.     } 
  8. let a = new A(100) 
  9. console.log(a)              // A {count: 100} 
  10. console.log(a.toString())   // 我有這么多錢(qián):100 
  11. console.log(a + 1)          // 我有這么多錢(qián):1001

Nice.

valueOf

返回當(dāng)前對(duì)象的原始值。

具體功能與toString大同小異,同樣具有以上的自動(dòng)調(diào)用和重寫(xiě)方法。

這里就沒(méi)什么好說(shuō)的了,主要為兩者間的區(qū)別,有請(qǐng)繼續(xù)往下看

 
 
 
  1. let c = [1, 2, 3] 
  2. let d = {a:2} 
  3. console.log(c.valueOf())    // [1, 2, 3] 
  4. console.log(d.valueOf())    // {a:2}

兩者區(qū)別

  •  共同點(diǎn):在輸出對(duì)象時(shí)會(huì)自動(dòng)調(diào)用。
  •  不同點(diǎn):默認(rèn)返回值不同,且存在優(yōu)先級(jí)關(guān)系。

二者并存的情況下,在數(shù)值運(yùn)算中,優(yōu)先調(diào)用了valueOf,字符串運(yùn)算中,優(yōu)先調(diào)用了toString。

看代碼方可知曉:

 
 
 
  1. class A { 
  2.     valueOf() { 
  3.         return 2 
  4.     } 
  5.     toString() { 
  6.         return '哈哈哈' 
  7.     } 
  8. let a = new A() 
  9. console.log(String(a))  // '哈哈哈'   => (toString) 
  10. console.log(Number(a))  // 2         => (valueOf) 
  11. console.log(a + '22')   // '222'     => (valueOf) 
  12. console.log(a == 2)     // true      => (valueOf) 
  13. console.log(a === 2)    // false     => (嚴(yán)格等于不會(huì)觸發(fā)隱式轉(zhuǎn)換)

結(jié)果給人的感覺(jué)是,如果轉(zhuǎn)換為字符串時(shí)調(diào)用toString方法,如果是轉(zhuǎn)換為數(shù)值時(shí)則調(diào)用valueOf方法。

但其中的 a + '22' 很不和諧,字符串合拼應(yīng)該是調(diào)用toString方法。為了追究真相,我們需要更嚴(yán)謹(jǐn)?shù)膶?shí)驗(yàn)。

  •  暫且先把 valueOf 方法去掉
 
 
 
  1. class A { 
  2.     toString() { 
  3.         return '哈哈哈' 
  4.     } 
  5. let a = new A() 
  6. console.log(String(a))  // '哈哈哈'     => (toString) 
  7. console.log(Number(a))  // NaN         => (toString) 
  8. console.log(a + '22')   // '哈哈哈22'   => (toString) 
  9. console.log(a == 2)     // false       => (toString)
  •  去掉 toString 方法看看
 
 
 
  1. class A { 
  2.     valueOf() { 
  3.         return 2 
  4.     } 
  5. let a = new A() 
  6. console.log(String(a))  // '[object Object]'    => (toString) 
  7. console.log(Number(a))  // 2                    => (valueOf) 
  8. console.log(a + '22')   // '222'                => (valueOf) 
  9. console.log(a == 2)     // true                 => (valueOf)

發(fā)現(xiàn)有點(diǎn)不同吧?!它沒(méi)有像上面 toString 那樣統(tǒng)一規(guī)整。對(duì)于那個(gè) [object Object],我估計(jì)是從 Object 那里繼承過(guò)來(lái)的,我們?cè)偃サ羲纯础?/p>

 
 
 
  1. class A { 
  2.     valueOf() { 
  3.         return 2 
  4.     } 
  5. let a = new A() 
  6. Object.prototype.toString = null;  
  7. console.log(String(a))  // 2        => (valueOf) 
  8. console.log(Number(a))  // 2        => (valueOf) 
  9. console.log(a + '22')   // '222'    => (valueOf) 
  10. console.log(a == 2)     // true     => (valueOf)

總結(jié):valueOf偏向于運(yùn)算,toString偏向于顯示。

  1.  在進(jìn)行對(duì)象轉(zhuǎn)換時(shí),將優(yōu)先調(diào)用toString方法,如若沒(méi)有重寫(xiě) toString,將調(diào)用 valueOf 方法;如果兩個(gè)方法都沒(méi)有重寫(xiě),則按Object的toString輸出。
  2.  在進(jìn)行強(qiáng)轉(zhuǎn)字符串類(lèi)型時(shí),將優(yōu)先調(diào)用 toString 方法,強(qiáng)轉(zhuǎn)為數(shù)字時(shí)優(yōu)先調(diào)用 valueOf。
  3.  使用運(yùn)算操作符的情況下,valueOf的優(yōu)先級(jí)高于toString。

[Symbol.toPrimitive]

MDN:Symbol.toPrimitive 是一個(gè)內(nèi)置的 Symbol 值,它是作為對(duì)象的函數(shù)值屬性存在的,當(dāng)一個(gè)對(duì)象轉(zhuǎn)換為對(duì)應(yīng)的原始值時(shí),會(huì)調(diào)用此函數(shù)。

是不是有點(diǎn)懵???把它當(dāng)做一個(gè)函數(shù)就行了~~

  •  作用:同valueOf()和toString()一樣,但是優(yōu)先級(jí)要高于這兩者;
  •  該函數(shù)被調(diào)用時(shí),會(huì)被傳遞一個(gè)字符串參數(shù)

    hint

    ,表示當(dāng)前運(yùn)算的模式,一共有三種模式:

  •  string:字符串類(lèi)型
  •  number:數(shù)字類(lèi)型
  •  default:默認(rèn)

下面來(lái)看看實(shí)現(xiàn)吧:

 
 
 
  1. class A { 
  2.     constructor(count) {
  3.          this.count = count 
  4.     } 
  5.     valueOf() { 
  6.         return 2 
  7.     } 
  8.     toString() { 
  9.         return '哈哈哈' 
  10.     } 
  11.     // 我在這里 
  12.     [Symbol.toPrimitive](hint) { 
  13.         if (hint == "number") {
  14.              return 10; 
  15.         } 
  16.         if (hint == "string") { 
  17.             return "Hello Libai"; 
  18.         } 
  19.         return true; 
  20.     } 
  21. const a = new A(10) 
  22. console.log(`${a}`)     // 'Hello Libai' => (hint == "string") 
  23. console.log(String(a))  // 'Hello Libai' => (hint == "string") 
  24. console.log(+a)         // 10            => (hint == "number") 
  25. console.log(a * 20)     // 200           => (hint == "number")
  26. console.log(a / 20)     // 0.5           => (hint == "number") 
  27. console.log(Number(a))  // 10            => (hint == "number") 
  28. console.log(a + '22')   // 'true22'      => (hint == "default") 
  29. console.log(a == 10)     // false        => (hint == "default")

比較特殊的是(+)拼接符,這個(gè)屬于default的模式。

劃重點(diǎn):此方法不兼容IE,尷尬到我不想寫(xiě)出來(lái)了~~

面試題分析

以下幾道大廠必考的面試題,完美呈現(xiàn)出 toString 與 valueOf 的作用。

1. a===1&&a===2&&a===3 為 true

雙等號(hào)(==):會(huì)觸發(fā)隱式類(lèi)型轉(zhuǎn)換,所以可以使用 valueOf 或者 toString 來(lái)實(shí)現(xiàn)。

每次判斷都會(huì)觸發(fā)valueOf方法,同時(shí)讓value+1,才能使得下次判斷成立。

 
 
 
  1. class A { 
  2.     constructor(value) { 
  3.         this.value = value; 
  4.     } 
  5.     valueOf() { 
  6.         return this.value++; 
  7.     } 
  8. }
  9. const a = new A(1); 
  10. if (a == 1 && a == 2 && a == 3) { 
  11.     console.log("Hi Libai!"); 
  12. }

全等(===):嚴(yán)格等于不會(huì)進(jìn)行隱式轉(zhuǎn)換,這里使用 Object.defineProperty 數(shù)據(jù)劫持的方法來(lái)實(shí)現(xiàn)

 
 
 
  1. let value = 1; 
  2. Object.defineProperty(window, 'a', { 
  3.     get() { 
  4.         return value++ 
  5.     } 
  6. }) 
  7. if (a === 1 && a === 2 && a === 3) { 
  8.     console.log("Hi Libai!") 
  9. }

上面我們就是劫持全局window上面的a,當(dāng)a每一次做判斷的時(shí)候都會(huì)觸發(fā)get屬性獲取值,并且每一次獲取值都會(huì)觸發(fā)一次函數(shù)實(shí)行一次自增,判斷三次就自增三次,所以最后會(huì)讓公式成立。

  •  注:defineProperty 可參考這篇文章學(xué)習(xí),點(diǎn)我進(jìn)入傳送門(mén)
  •  自:大廠面試題分享:如何讓(a===1&&a===2&&a===3)的值為true?

2. 實(shí)現(xiàn)一個(gè)無(wú)限累加函數(shù)

問(wèn)題:用 JS 實(shí)現(xiàn)一個(gè)無(wú)限累加的函數(shù) add,示例如下:

 
 
 
  1. add(1); // 1 
  2. add(1)(2);  // 3 
  3. add(1)(2)(3); // 6 
  4. add(1)(2)(3)(4); // 10  
  5. // 以此類(lèi)推 
  6. function add(a) { 
  7.     function sum(b) { // 使用閉包 
  8.         a = b ? a + b : a; // 累加 
  9.         return sum; 
  10.     } 
  11.     sum.toString = function() { // 只在最后一次調(diào)用 
  12.         return a; 
  13.     } 
  14.     return sum; // 返回一個(gè)函數(shù) 
  15. add(1)              // 1 
  16. add(1)(2)           // 3 
  17. add(1)(2)(3)        // 6 
  18. add(1)(2)(3)(4)     // 10 
  •  add函數(shù)內(nèi)部定義sum函數(shù)并返回,實(shí)現(xiàn)連續(xù)調(diào)用
  •  sum函數(shù)形成了一個(gè)閉包,每次調(diào)用進(jìn)行累加值,再返回當(dāng)前函數(shù)sum
  •  add()每次都會(huì)返回一個(gè)函數(shù)sum,直到最后一個(gè)沒(méi)被調(diào)用,默認(rèn)會(huì)觸發(fā)toString方法,所以我們這里重寫(xiě)toString方法,并返回累計(jì)的最終值a

這樣說(shuō)才能理解:

add(10): 執(zhí)行函數(shù)add(10),返回了sum函數(shù),注意這一次沒(méi)有調(diào)用sum,默認(rèn)執(zhí)行sum.toString方法。所以輸出10;

add(10)(20): 執(zhí)行函數(shù)add(10),返回sum(此時(shí)a為10),再執(zhí)行sum(20),此時(shí)a為30,返回sum,最后調(diào)用sum.toString()輸出30。add(10)(20)...(n)依次類(lèi)推。

3. 柯里化實(shí)現(xiàn)多參累加

這里是上面累加的升級(jí)版,實(shí)現(xiàn)多參數(shù)傳遞累加。

 
 
 
  1. add(1)(3,4)(3,5)    // 16 
  2. add(2)(2)(3,5)      // 12 
  3. function add(){ 
  4.     // 1 把所有參數(shù)轉(zhuǎn)換成數(shù)組 
  5.     let args = Array.prototype.slice.call(arguments) 
  6.     // 2 再次調(diào)用add函數(shù),傳遞合并當(dāng)前與之前的參數(shù) 
  7.     let fn = function() { 
  8.         let arg_fn = Array.prototype.slice.call(arguments) 
  9.         return add.apply(null, args.concat(arg_fn)) 
  10.     } 
  11.     // 3 最后默認(rèn)調(diào)用,返回合并的值 
  12.     fn.toString = function() { 
  13.         return args.reduce(function(a, b) { 
  14.             return a + b 
  15.         }) 
  16.     } 
  17.     return fn 
  18. // ES6寫(xiě)法 
  19. function add () { 
  20.     let args = [...arguments]; 
  21.     let fn = function(){ 
  22.         return add.apply(null, args.concat([...arguments])) 
  23.     } 
  24.      fn.toString = () => args.reduce((a, b) => a + b) 
  25.     return fn; 
  26. }

當(dāng)前文章:全面分析toString與valueOf,并隨手解決掉幾道大廠必備面試題
本文鏈接:http://www.5511xx.com/article/coijese.html