怎么對(duì)javascript的類型進(jìn)行轉(zhuǎn)換

本文章向大家介紹怎么對(duì)javascript的類型進(jìn)行轉(zhuǎn)換的基本知識(shí)點(diǎn)總結(jié)和需要注意事項(xiàng),具有一定的參考價(jià)值,需要的朋友可以參考一下。

創(chuàng)新互聯(lián)建站從2013年開始,先為玉樹等服務(wù)建站,玉樹等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢服務(wù)。為玉樹企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問題。

JavaScript可以做什么

1.可以使網(wǎng)頁(yè)具有交互性,例如響應(yīng)用戶點(diǎn)擊,給用戶提供更好的體驗(yàn)。 2.可以處理表單,檢驗(yàn)用戶的輸入,并提供及時(shí)反饋節(jié)省用戶時(shí)間。 3.可以根據(jù)用戶的操作,動(dòng)態(tài)的創(chuàng)建頁(yè)面。 4使用JavaScript可以通過設(shè)置cookie存儲(chǔ)在瀏覽器上的一些臨時(shí)信息。

實(shí)現(xiàn)一個(gè)函數(shù),運(yùn)算結(jié)果可以滿足如下預(yù)期結(jié)果:

add(1)(2) // 3
add(1, 2, 3)(10) // 16
add(1)(2)(3)(4)(5) // 15

對(duì)于一個(gè)好奇的切圖仔來說,忍不住動(dòng)手嘗試了一下,看到題目首先想到的是會(huì)用到高階函數(shù)以及 Array.prototype.reduce()

高階函數(shù)(Higher-order function):高階函數(shù)的意思是它接收另一個(gè)函數(shù)作為參數(shù)。在 javascript 中,函數(shù)是一等公民,允許函數(shù)作為參數(shù)或者返回值傳遞。

得到了下面這個(gè)解法:

function add() {
 var args = Array.prototype.slice.call(arguments);
  return function() {
  var arg2 = Array.prototype.slice.call(arguments);
  return args.concat(arg2).reduce(function(a, b){
   return a + b;
  });
 }
}

驗(yàn)證了一下,發(fā)現(xiàn)錯(cuò)了:

add(1)(2) // 3
add(1, 2)(3) // 6
add(1)(2)(3) // Uncaught TypeError: add(...)(...) is not a function(…)

上面的解法,只有在 add()()情形下是正確的。而當(dāng)鏈?zhǔn)讲僮鞯膮?shù)多于兩個(gè)或者少于兩個(gè)的時(shí)候,無法返回結(jié)果。

而這個(gè)也是這題的一個(gè)難點(diǎn)所在,add()的時(shí)候,如何既返回一個(gè)值又返回一個(gè)函數(shù)以供后續(xù)繼續(xù)調(diào)用?

后來經(jīng)過高人指點(diǎn),通過重寫函數(shù)的 valueOf方法或者 toString方法,可以得到其中一種解法:

function add () {
 var args = Array.prototype.slice.call(arguments);
 var fn = function () {
  var arg_fn = Array.prototype.slice.call(arguments);
  return add.apply(null, args.concat(arg_fn));
 }
 fn.valueOf = function () {
  return args.reduce(function(a, b) {
   return a + b;
  })
 }
 return fn;
}

嗯?第一眼看到這個(gè)解法的時(shí)候,我是懵逼的。因?yàn)槲腋杏X fn.valueOf()從頭到尾都沒有被調(diào)用過,但是驗(yàn)證了下結(jié)果:

add(1) // 1
add(1,2)(3) //6
add(1)(2)(3)(4)(5) // 15

神奇的對(duì)了!那么玄機(jī)必然是在上面的 fn.valueOf = function() {}內(nèi)了。為何會(huì)是這樣呢?這個(gè)方法是在函數(shù)的什么時(shí)刻執(zhí)行的?且聽我一步一步道來。

valueOf 和 toString

先來簡(jiǎn)單了解下這兩個(gè)方法:

Object.prototype.valueOf()

用 MDN 的話來說,valueOf() 方法返回指定對(duì)象的原始值。

JavaScript 調(diào)用 valueOf() 方法用來把對(duì)象轉(zhuǎn)換成原始類型的值(數(shù)值、字符串和布爾值)。但是我們很少需要自己調(diào)用此函數(shù),valueOf 方法一般都會(huì)被 JavaScript 自動(dòng)調(diào)用。

記住上面這句話,下面我們會(huì)細(xì)說所謂的自動(dòng)調(diào)用是什么意思。

Object.prototype.toString()

toString() 方法返回一個(gè)表示該對(duì)象的字符串。

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

這里先記住,valueOf() 和 toString() 在特定的場(chǎng)合下會(huì)自行調(diào)用。

原始類型

好,鋪墊一下,先了解下 javascript 的幾種原始類型,除去 Object 和 Symbol,有如下幾種原始類型:

  • Number

  • String

  • Boolean

  • Undefined

  • Null

在 JavaScript 進(jìn)行對(duì)比或者各種運(yùn)算的時(shí)候會(huì)把對(duì)象轉(zhuǎn)換成這些類型,從而進(jìn)行后續(xù)的操作,下面逐一說明:

String 類型轉(zhuǎn)換

在某個(gè)操作或者運(yùn)算需要字符串的時(shí)候,會(huì)觸發(fā) Object 的 String 轉(zhuǎn)換,舉個(gè)例子:

var obj = {name: 'Coco'};
var str = '123' + obj;
console.log(str); // 123[object Object]

轉(zhuǎn)換規(guī)則:

  • 如果 toString方法存在并且返回原始類型,返回 toString的結(jié)果。

  • 如果 toString方法不存在或者返回的不是“原始類型”,調(diào)用valueOf方法,如果 valueOf方法存在,并且返回“原始類型”數(shù)據(jù),返回 valueOf的結(jié)果。

  • 其他情況,拋出錯(cuò)誤。

上面的例子實(shí)際上是:

var obj = {name: 'Coco'};
var str = '123' + obj.toString();

其中,obj.toString()的值為 "[object Object]"。

假設(shè)是數(shù)組:

var arr = [1, 2];
var str = '123' + arr;
console.log(str); // 1231,2

上面 + arr其實(shí)是調(diào)用了 + arr.toString()。

但是,我們可以自己改寫對(duì)象的 toString,valueOf 方法:

var obj = {
  toString: function() {
    console.log('調(diào)用了 obj.toString');
    return '111';
  }
}
alert(obj);
// 調(diào)用了 obj.toString
// 111

上面 alert(obj),obj 會(huì)自動(dòng)調(diào)用自己的 obj.toString()方法轉(zhuǎn)化為原始類型,如果我們不重寫它的 toString方法,將輸出 [object Object],這里我們重寫了 toString,而且返回了一個(gè)原始類型字符串 111 ,所以最終 alert 出了 111。

上面的轉(zhuǎn)化規(guī)則寫了,toString 方法需要存在并且返回原始類型,那么如果返回的不是一個(gè)原始類型,則會(huì)去繼續(xù)尋找對(duì)象的 valueOf 方法:

下面我們嘗試證明如果 toString()方法不可用的時(shí)候系統(tǒng)會(huì)調(diào)用 valueOf()方法,下面我們改寫對(duì)象的 valueOf

var obj = {
  toString: function() {
    console.log('調(diào)用了 obj.toString');
    return {};
  },
  valueOf: function() {
    console.log('調(diào)用了 obj.valueOf')
    return '110';
  }
}
alert(obj);
// 調(diào)用了 obj.toString
// 調(diào)用了 obj.valueOf
// 110

從結(jié)果可以看到,當(dāng) toString 不可用的時(shí)候,系統(tǒng)會(huì)再嘗試 valueOf 方法,如果 valueOf 方法存在,并且返回原始類型(String、Number、Boolean)數(shù)據(jù),返回valueOf的結(jié)果。

那么如果,toString 和 valueOf 返回的都不是原始類型呢?看下面這個(gè)例子:

var obj = {
  toString: function() {
    console.log('調(diào)用了 obj.toString');
    return {};
  },
  valueOf: function() {
    console.log('調(diào)用了 obj.valueOf')
    return {};
  }
}
alert(obj);
// 調(diào)用了 obj.toString
// 調(diào)用了 obj.valueOf
// Uncaught TypeError: Cannot convert object to primitive value

可以發(fā)現(xiàn),如果 toStringvalueOf方法均不可用的情況下,系統(tǒng)會(huì)直接返回一個(gè)錯(cuò)誤。

Number 類型轉(zhuǎn)換

上面描述的是String類型的轉(zhuǎn)換,很多時(shí)候也會(huì)發(fā)生Number類型的轉(zhuǎn)換:

  • 調(diào)用 Number() 函數(shù),強(qiáng)制進(jìn)行 Number 類型轉(zhuǎn)換

  • 調(diào)用 Math.sqrt() 這類參數(shù)需要 Number 類型的方法

  • obj == 1,進(jìn)行對(duì)比的時(shí)候

  • obj + 1, 進(jìn)行運(yùn)算的時(shí)候

與 String 類型轉(zhuǎn)換相似,但是 Number 類型剛好反過來,先查詢自身的 valueOf方法,再查詢自己 toString方法:

  1. 如果 valueOf 存在,且返回原始類型數(shù)據(jù),返回 valueOf 的結(jié)果。

  2. 如果 toString 存在,且返回原始類型數(shù)據(jù),返回 toString 的結(jié)果。

  3. 其他情況,拋出錯(cuò)誤。

按照上述步驟,分別嘗試一下:

var obj = {
  valueOf: function() {
    console.log('調(diào)用 valueOf');
    return 5;
  }
}
console.log(obj + 1);
// 調(diào)用 valueOf
// 6
var obj = {
  valueOf: function() {
    console.log('調(diào)用 valueOf');
    return {};
  },
  toString: function() {
    console.log('調(diào)用 toString');
    return 10;
  }
}
console.log(obj + 1);
// 調(diào)用 valueOf
// 調(diào)用 toString
// 11
var obj = {
  valueOf: function() {
    console.log('調(diào)用 valueOf');
    return {};
  },
  toString: function() {
    console.log('調(diào)用 toString');
    return {};
  }
}
console.log(obj + 1);
// 調(diào)用 valueOf
// 調(diào)用 toString
// Uncaught TypeError: Cannot convert object to primitive value

Boolean 轉(zhuǎn)換

什么時(shí)候會(huì)進(jìn)行布爾轉(zhuǎn)換呢:

  • 布爾比較時(shí)

  • if(obj) , while(obj) 等判斷時(shí)

簡(jiǎn)單來說,除了下述 6 個(gè)值轉(zhuǎn)換結(jié)果為 false,其他全部為 true:

  • undefined

  • null

  • -0

  • 0或+0

  • NaN

  • ''(空字符串)

Boolean(undefined) // false
Boolean(null) // false
Boolean(0) // false
Boolean(NaN) // false
Boolean('') // false 

Function 轉(zhuǎn)換

好,最后回到我們一開始的題目,來講講函數(shù)的轉(zhuǎn)換。

我們定義一個(gè)函數(shù)如下:

function test() {
  var a = 1;
  console.log(1);
}

如果我們僅僅是調(diào)用 test而不是 test(),看看會(huì)發(fā)生什么?

可以看到,這里把我們定義的 test 函數(shù)的重新打印了一遍,其實(shí),這里自行調(diào)用了函數(shù)的 valueOf方法:

我們改寫一下 test 函數(shù)的 valueOf 方法。

test.valueOf = function() {
  console.log('調(diào)用 valueOf 方法');
  return 2;
} 
test;
// 輸出如下:
// 調(diào)用 valueOf 方法
// 2

與 Number 轉(zhuǎn)換類似,如果函數(shù)的 valueOf方法返回的不是一個(gè)原始類型,會(huì)繼續(xù)找到它的 toString方法:

test.valueOf = function() {
  console.log('調(diào)用 valueOf 方法');
  return {};
}
test.toString= function() {
  console.log('調(diào)用 toString 方法');
  return 3;
}
test;
// 輸出如下:
// 調(diào)用 valueOf 方法
// 調(diào)用 toString 方法
// 3

破題

再看回我正文開頭那題的答案,正是運(yùn)用了函數(shù)會(huì)自行調(diào)用 valueOf方法這個(gè)技巧,并改寫了該方法。我們稍作改變,變形如下:

function add () {
  console.log('進(jìn)入add');
  var args = Array.prototype.slice.call(arguments);
  var fn = function () {
    var arg_fn = Array.prototype.slice.call(arguments);
    console.log('調(diào)用fn');
    return add.apply(null, args.concat(arg_fn));
  }
  fn.valueOf = function () {
    console.log('調(diào)用valueOf');
    return args.reduce(function(a, b) {
      return a + b;
    })
  }
  return fn;
}

當(dāng)調(diào)用一次 add 的時(shí)候,實(shí)際是是返回 fn 這個(gè) function,實(shí)際是也就是返回 fn.valueOf();

add(1);
// 輸出如下:
// 進(jìn)入add
// 調(diào)用valueOf
// 1

其實(shí)也就是相當(dāng)于:

[1].reduce(function(a, b) {
  return a + b;
})
// 1

當(dāng)鏈?zhǔn)秸{(diào)用兩次的時(shí)候:

add(1)(2);
// 輸出如下:
// 進(jìn)入add
// 調(diào)用fn
// 進(jìn)入add
// 調(diào)用valueOf
// 3

當(dāng)鏈?zhǔn)秸{(diào)用三次的時(shí)候:

add(1)(2)(3);
// 輸出如下:
// 進(jìn)入add
// 調(diào)用fn
// 進(jìn)入add
// 調(diào)用fn
// 進(jìn)入add
// 調(diào)用valueOf
// 6

可以看到,這里其實(shí)有一種循環(huán)。只有最后一次調(diào)用才真正調(diào)用到 valueOf,而之前的操作都是合并參數(shù),遞歸調(diào)用本身,由于最后一次調(diào)用返回的是一個(gè) fn 函數(shù),所以最終調(diào)用了函數(shù)的 fn.valueOf,并且利用了 reduce方法對(duì)所有參數(shù)求和。

除了改寫 valueOf方法,也可以改寫 toString方法,所以,如果你喜歡,下面這樣也可以:

function add () {
  var args = Array.prototype.slice.call(arguments);
  var fn = function () {
    var arg_fn = Array.prototype.slice.call(arguments);
    return add.apply(null, args.concat(arg_fn));
  }
  fn.toString = function() {
    return args.reduce(function(a, b) {
      return a + b;
    })
  }
  return fn;
}

這里有個(gè)規(guī)律,如果只改寫 valueOf()或是 toString()其中一個(gè),會(huì)優(yōu)先調(diào)用被改寫了的方法,而如果兩個(gè)同時(shí)改寫,則會(huì)像 String 轉(zhuǎn)換規(guī)則一樣,優(yōu)先查詢 valueOf()方法,在 valueOf()方法返回的是非原始類型的情況下再查詢 toString()方法。

以上就是小編為大家?guī)淼脑趺磳?duì)javascript的類型進(jìn)行轉(zhuǎn)換的全部?jī)?nèi)容了,希望大家多多支持創(chuàng)新互聯(lián)!

分享題目:怎么對(duì)javascript的類型進(jìn)行轉(zhuǎn)換
標(biāo)題鏈接:http://bm7419.com/article14/jdiide.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供靜態(tài)網(wǎng)站、全網(wǎng)營(yíng)銷推廣網(wǎng)站維護(hù)、虛擬主機(jī)、小程序開發(fā)、網(wǎng)站策劃

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

商城網(wǎng)站建設(shè)