這篇文章主要介紹“如何理解toString與valueOf”,在日常操作中,相信很多人在如何理解toString與valueOf問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”如何理解toString與valueOf”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
我們提供的服務有:成都網(wǎng)站建設(shè)、成都網(wǎng)站制作、微信公眾號開發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認證、陸川ssl等。為上1000家企事業(yè)單位解決了網(wǎng)站和推廣的問題。提供周到的售前咨詢和貼心的售后服務,是有科學管理、有技術(shù)的陸川網(wǎng)站制作公司
基本上,所有JS數(shù)據(jù)類型都擁有這兩個方法,null除外。它們倆是位于原型鏈上的方法,也是為了解決javascript值運算與顯示的問題。
valueOf 和 toString 幾乎都是在出現(xiàn)操作符(+-*/==><)時被調(diào)用(隱式轉(zhuǎn)換)。
toString
返回一個表示該對象的字符串,當對象表示為文本值或以期望的字符串方式被引用時,toString方法被自動調(diào)用。
1. 手動調(diào)用看看什么效果
嗯,跟介紹的一樣,沒騙人,全部都轉(zhuǎn)成了字符串。
比較特殊的地方就是,表示對象的時候,變成[object Object],表示數(shù)組的時候,就變成數(shù)組內(nèi)容以逗號連接的字符串,相當于Array.join(',')。
let a = {} let b = [1, 2, 3] let c = '123' let d = function(){ console.log('fn') } console.log(a.toString()) // '[object Object]' console.log(b.toString()) // '1,2,3' console.log(c.toString()) // '123' console.log(d.toString()) // 'function(){ console.log('fn') }'
2. 最精準的類型判斷
這種屬于更精確的判斷方式,在某種場合會比使用 typeof & instanceof 來的更高效和準確些。
toString.call(()=>{}) // [object Function] toString.call({}) // [object Object] toString.call([]) // [object Array] toString.call('') // [object String] toString.call(22) // [object Number] toString.call(undefined) // [object undefined] toString.call(null) // [object null] toString.call(new Date) // [object Date] toString.call(Math) // [object Math] toString.call(window) // [object Window]
3. 什么時候會自動調(diào)用呢
使用操作符的時候,如果其中一邊為對象,則會先調(diào)用toSting方法,也就是隱式轉(zhuǎn)換,然后再進行操作。
let c = [1, 2, 3] let d = {a:2} Object.prototype.toString = function(){ console.log('Object') } Array.prototype.toString = function(){ console.log('Array') return this.join(',') // 返回toString的默認值(下面測試) } Number.prototype.toString = function(){ console.log('Number') } String.prototype.toString = function(){ console.log('String') } console.log(2 + 1) // 3 console.log('s') // 's' console.log('s'+2) // 's2' console.log(c < 2) // false (一次 => 'Array') console.log(c + c) // "1,2,31,2,3" (兩次 => 'Array') console.log(d > d) // false (兩次 => 'Object')
4. 重寫toString方法
既然知道了有 toString 這個默認方法,那我們也可以來重寫這個方法
class A { constructor(count) { this.count = count } toString() { return '我有這么多錢:' + this.count } } let a = new A(100) console.log(a) // A {count: 100} console.log(a.toString()) // 我有這么多錢:100 console.log(a + 1) // 我有這么多錢:1001
Nice.
valueOf
返回當前對象的原始值。
具體功能與toString大同小異,同樣具有以上的自動調(diào)用和重寫方法。
這里就沒什么好說的了,主要為兩者間的區(qū)別,有請繼續(xù)往下看??
let c = [1, 2, 3] let d = {a:2} console.log(c.valueOf()) // [1, 2, 3] console.log(d.valueOf()) // {a:2}
兩者區(qū)別
共同點:在輸出對象時會自動調(diào)用。
不同點:默認返回值不同,且存在優(yōu)先級關(guān)系。
二者并存的情況下,在數(shù)值運算中,優(yōu)先調(diào)用了valueOf,字符串運算中,優(yōu)先調(diào)用了toString。
看代碼方可知曉:
class A { valueOf() { return 2 } toString() { return '哈哈哈' } } let a = new A() console.log(String(a)) // '哈哈哈' => (toString) console.log(Number(a)) // 2 => (valueOf) console.log(a + '22') // '222' => (valueOf) console.log(a == 2) // true => (valueOf) console.log(a === 2) // false => (嚴格等于不會觸發(fā)隱式轉(zhuǎn)換)
結(jié)果給人的感覺是,如果轉(zhuǎn)換為字符串時調(diào)用toString方法,如果是轉(zhuǎn)換為數(shù)值時則調(diào)用valueOf方法。
但其中的 a + '22' 很不和諧,字符串合拼應該是調(diào)用toString方法。為了追究真相,我們需要更嚴謹?shù)膶嶒灐?/p>
暫且先把 valueOf 方法去掉
class A { toString() { return '哈哈哈' } } let a = new A() console.log(String(a)) // '哈哈哈' => (toString) console.log(Number(a)) // NaN => (toString) console.log(a + '22') // '哈哈哈22' => (toString) console.log(a == 2) // false => (toString)
去掉 toString 方法看看
class A { valueOf() { return 2 } } let a = new A() console.log(String(a)) // '[object Object]' => (toString) console.log(Number(a)) // 2 => (valueOf) console.log(a + '22') // '222' => (valueOf) console.log(a == 2) // true => (valueOf)
發(fā)現(xiàn)有點不同吧?!它沒有像上面 toString 那樣統(tǒng)一規(guī)整。對于那個 [object Object],我估計是從 Object 那里繼承過來的,我們再去掉它看看。
class A { valueOf() { return 2 } } let a = new A() Object.prototype.toString = null; console.log(String(a)) // 2 => (valueOf) console.log(Number(a)) // 2 => (valueOf) console.log(a + '22') // '222' => (valueOf) console.log(a == 2) // true => (valueOf)
總結(jié):valueOf偏向于運算,toString偏向于顯示。
在進行對象轉(zhuǎn)換時,將優(yōu)先調(diào)用toString方法,如若沒有重寫 toString,將調(diào)用 valueOf 方法;如果兩個方法都沒有重寫,則按Object的toString輸出。
在進行強轉(zhuǎn)字符串類型時,將優(yōu)先調(diào)用 toString 方法,強轉(zhuǎn)為數(shù)字時優(yōu)先調(diào)用 valueOf。
使用運算操作符的情況下,valueOf的優(yōu)先級高于toString。
[Symbol.toPrimitive]
MDN:Symbol.toPrimitive 是一個內(nèi)置的 Symbol 值,它是作為對象的函數(shù)值屬性存在的,當一個對象轉(zhuǎn)換為對應的原始值時,會調(diào)用此函數(shù)。
是不是有點懵???把它當做一個函數(shù)就行了~~
作用:同valueOf()和toString()一樣,但是優(yōu)先級要高于這兩者;
該函數(shù)被調(diào)用時,會被傳遞一個字符串參數(shù)
hint
,表示當前運算的模式,一共有三種模式:
string:字符串類型
number:數(shù)字類型
default:默認
下面來看看實現(xiàn)吧:
class A { constructor(count) { this.count = count } valueOf() { return 2 } toString() { return '哈哈哈' } // 我在這里 [Symbol.toPrimitive](hint) { if (hint == "number") { return 10; } if (hint == "string") { return "Hello Libai"; } return true; } } const a = new A(10) console.log(`${a}`) // 'Hello Libai' => (hint == "string") console.log(String(a)) // 'Hello Libai' => (hint == "string") console.log(+a) // 10 => (hint == "number") console.log(a * 20) // 200 => (hint == "number") console.log(a / 20) // 0.5 => (hint == "number") console.log(Number(a)) // 10 => (hint == "number") console.log(a + '22') // 'true22' => (hint == "default") console.log(a == 10) // false => (hint == "default")
比較特殊的是(+)拼接符,這個屬于default的模式。
劃重點:此方法不兼容IE,尷尬到我不想寫出來了~~
面試題分析
以下幾道大廠必考的面試題,完美呈現(xiàn)出 toString 與 valueOf 的作用。
1. a===1&&a===2&&a===3 為 true
雙等號(==):會觸發(fā)隱式類型轉(zhuǎn)換,所以可以使用 valueOf 或者 toString 來實現(xiàn)。
每次判斷都會觸發(fā)valueOf方法,同時讓value+1,才能使得下次判斷成立。
class A { constructor(value) { this.value = value; } valueOf() { return this.value++; } } const a = new A(1); if (a == 1 && a == 2 && a == 3) { console.log("Hi Libai!"); }
全等(===):嚴格等于不會進行隱式轉(zhuǎn)換,這里使用 Object.defineProperty 數(shù)據(jù)劫持的方法來實現(xiàn)
let value = 1; Object.defineProperty(window, 'a', { get() { return value++ } }) if (a === 1 && a === 2 && a === 3) { console.log("Hi Libai!") }
上面我們就是劫持全局window上面的a,當a每一次做判斷的時候都會觸發(fā)get屬性獲取值,并且每一次獲取值都會觸發(fā)一次函數(shù)實行一次自增,判斷三次就自增三次,所以最后會讓公式成立。
2. 實現(xiàn)一個無限累加函數(shù)
問題:用 JS 實現(xiàn)一個無限累加的函數(shù) add,示例如下:
add(1); // 1 add(1)(2); // 3 add(1)(2)(3); // 6 add(1)(2)(3)(4); // 10 // 以此類推 function add(a) { function sum(b) { // 使用閉包 a = b ? a + b : a; // 累加 return sum; } sum.toString = function() { // 只在最后一次調(diào)用 return a; } return sum; // 返回一個函數(shù) } add(1) // 1 add(1)(2) // 3 add(1)(2)(3) // 6 add(1)(2)(3)(4) // 10
add函數(shù)內(nèi)部定義sum函數(shù)并返回,實現(xiàn)連續(xù)調(diào)用
sum函數(shù)形成了一個閉包,每次調(diào)用進行累加值,再返回當前函數(shù)sum
add()每次都會返回一個函數(shù)sum,直到最后一個沒被調(diào)用,默認會觸發(fā)toString方法,所以我們這里重寫toString方法,并返回累計的最終值a
這樣說才能理解:
add(10): 執(zhí)行函數(shù)add(10),返回了sum函數(shù),注意這一次沒有調(diào)用sum,默認執(zhí)行sum.toString方法。所以輸出10;
add(10)(20): 執(zhí)行函數(shù)add(10),返回sum(此時a為10),再執(zhí)行sum(20),此時a為30,返回sum,最后調(diào)用sum.toString()輸出30。add(10)(20)...(n)依次類推。
3. 柯里化實現(xiàn)多參累加
這里是上面累加的升級版,實現(xiàn)多參數(shù)傳遞累加。
add(1)(3,4)(3,5) // 16 add(2)(2)(3,5) // 12 function add(){ // 1 把所有參數(shù)轉(zhuǎn)換成數(shù)組 let args = Array.prototype.slice.call(arguments) // 2 再次調(diào)用add函數(shù),傳遞合并當前與之前的參數(shù) let fn = function() { let arg_fn = Array.prototype.slice.call(arguments) return add.apply(null, args.concat(arg_fn)) } // 3 最后默認調(diào)用,返回合并的值 fn.toString = function() { return args.reduce(function(a, b) { return a + b }) } return fn } // ES6寫法 function add () { let args = [...arguments]; let fn = function(){ return add.apply(null, args.concat([...arguments])) } fn.toString = () => args.reduce((a, b) => a + b) return fn; }
到此,關(guān)于“如何理解toString與valueOf”的學習就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續(xù)學習更多相關(guān)知識,請繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>
文章標題:如何理解toString與valueOf
分享鏈接:http://www.rwnh.cn/article40/jeedeo.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站建設(shè)、網(wǎng)站設(shè)計、企業(yè)建站、網(wǎng)站收錄、App設(shè)計、網(wǎng)站制作
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)