- 1.
JavaScript
規(guī)定了幾種語言類型 - 2.
JavaScript
對象的底層數(shù)據(jù)結(jié)構(gòu)是什么 - 3.
Symbol
類型在實(shí)際開發(fā)中的應(yīng)用、可手動實(shí)現(xiàn)一個簡單的Symbol
- 4.
JavaScript
中的變量在內(nèi)存中的具體存儲形式 - 5.基本類型對應(yīng)的內(nèi)置對象缔刹,以及他們之間的裝箱拆箱操作
- 6.理解值類型和引用類型
- 7.
null
和undefined
的區(qū)別 - 8.至少可以說出三種判斷
JavaScript
數(shù)據(jù)類型的方式癌幕,以及他們的優(yōu)缺點(diǎn),如何準(zhǔn)確的判斷數(shù)組類型 - 9.可能發(fā)生隱式類型轉(zhuǎn)換的場景以及轉(zhuǎn)換原則绒净,應(yīng)如何避免或巧妙應(yīng)用
- 10.出現(xiàn)小數(shù)精度丟失的原因,
JavaScript
可以存儲的最大數(shù)字、最大安全數(shù)字鲁捏,JavaScript
處理大數(shù)字的方法、避免精度丟失的方法
1.JavaScript規(guī)定了幾種語言類型
JavaScript中的每一個值都有它自己的類型萧芙,JavaScript規(guī)定了七種語言類型:
- Undefined:未定義给梅,聲明了變量但是沒有賦值
var m;
console.log(s); //undefined ,如果一個沒有聲明的變量双揪,會報(bào)錯
- Null:空
var m=null;
console.log(m); //null
console.log(typeof(m)); //object
//咦动羽?為什么是object?這實(shí)際上是涉及到JavaScript內(nèi)部的存儲機(jī)制渔期,js中的數(shù)據(jù)在底層是以二進(jìn)制存儲
//如果前三位為0运吓,那么就會判定為object渴邦,而null的所有都為0,自然也就是object類型了拘哨,記住就好了谋梭,特殊情況特殊處理。
- Boolean:布爾值(true/false)
var m=true;
console.log(typeof(m)); //boolean
- String :表示字符串類型
var test0='test';
console.log(typeof(test0));//返回 string
var test1=new String('test');
console.log(typeof(test1));//返回 object
- Number:表示數(shù)字
var m=1;
console.log(typeof(m)); //輸出 number
- Symbol:(在 ECMAScript 6 中新添加的類型))一種數(shù)據(jù)類型倦青,它的實(shí)例是唯一且不可改變的
var s=Symbol('添加描述');
console.log(s); //Symbol(添加描述)
console.log(typeof(s)); //symbol
let s1 = Symbol('foo'); let s2 = Symbol('foo');
s1 === s2 // false
- Object
var obj={};
function fun(){};
var arr=[];
var date=new Date();
var er=new Error('ssss');
console.log(typeof(obj));//object
console.log(typeof(fun));//function
console.log(typeof(fun.prototype));//object
console.log(typeof(arr));//object
console.log(typeof(date));//object
console.log(er);//Error:ssss
2. JavaScript對象的底層數(shù)據(jù)結(jié)構(gòu)是什么
引擎層的 Object 類瓮床,然后 HeapObject 往下派生,每個 heap object 都有個 map 來記錄相關(guān)信息。
所有js對象都是基于一個名為HeapObject的類生成的产镐。生成對象的時候隘庄,引擎通過這個類向Heap申請空間。這個分配過程基本都是引擎自己實(shí)現(xiàn)癣亚,而不會調(diào)用malloc峭沦,因?yàn)橐獙?shí)現(xiàn)精確GC
3. Symbol類型在實(shí)際開發(fā)中的應(yīng)用、可手動實(shí)現(xiàn)一個簡單的Symbol
- 場景一:使用Symbol來作為對象屬性名key
特性:Symbol類型的key是不能通過Object.keys()或者for...in來枚舉的逃糟,它未被包含在對象自身的屬性名集合(property names)之中吼鱼。所以,利用該特性绰咽,我們可以把一些不需要對外操作和訪問的屬性使用Symbol來定義菇肃。也正因?yàn)檫@樣一個特性,當(dāng)使用JSON.stringify()將對象轉(zhuǎn)換成JSON字符串的時候取募,Symbol屬性也會被排除在輸出內(nèi)容之外琐谤。
let obj = {
[Symbol('name')]: 'zzz',
age: 18,
title: 'Engineer'
}
Object.keys(obj) // ['age', 'title']
for (let p in obj) {
console.log(p) // 分別會輸出:'age' 和 'title'
}
Object.getOwnPropertyNames(obj) // ['age', 'title']
JSON.stringify(obj) // {"age":18,"title":"Engineer"}
好處:我們可以利用這一特點(diǎn)來更好的設(shè)計(jì)我們的數(shù)據(jù)對象,讓“對內(nèi)操作”和“對外選擇性輸出”變得更加優(yōu)雅
會有一些專門針對Symbol的API獲取以Symbol方式定義的對象屬性
// 使用Object的API
Object.getOwnPropertySymbols(obj) // [Symbol(name)]
// 使用新增的反射API
Reflect.ownKeys(obj) // [Symbol(name), 'age', 'title']
- 場景二:使用Symbol代替常量
/*
const TYPE_AUDIO = 'AUDIO'
const TYPE_VIDEO = 'VIDEO'
const TYPE_IMAGE = 'IMAGE'
*/
const TYPE_AUDIO = Symbol()
const TYPE_VIDEO = Symbol()
const TYPE_IMAGE = Symbol()//保證變量的唯一性玩敏,但是這種場景意義不是很大斗忌,少了一些特定變量名稱的粘貼復(fù)制吧,const聲明的就是唯一值了
function handleFileResource(resource) {
switch(resource.type) {
case TYPE_AUDIO:
playAudio(resource)
break
case TYPE_VIDEO:
playVideo(resource)
break
case TYPE_IMAGE:
previewImage(resource)
break
default:
throw new Error('Unknown type of resource')
}
}
- 場景三:使用Symbol定義類的私有屬性/方法
在JavaScript中旺聚,是沒有如Java等面向?qū)ο笳Z言的訪問控制關(guān)鍵字private的织阳,類上所有定義的屬性或方法都是可公開訪問的。因此這對我們進(jìn)行API的設(shè)計(jì)時造成了一些困擾砰粹。
而有了Symbol以及模塊化機(jī)制唧躲,類的私有屬性和方法才變成可能。例如:
在文件 a.js中:
const PASSWORD = Symbol()
class Login {
constructor(username, password) {
this.username = username
this[PASSWORD] = password
}
checkPassword(pwd) {
return this[PASSWORD] === pwd
}
}
export default Login
在文件b中:
import Login from './a'
const login = new Login('admin', '123456')
login.checkPassword('123456') // true
login.PASSWORD // oh!no!
login[PASSWORD] // oh!no!
login["PASSWORD"] // oh!no!
由于Symbol常量PASSWORD被定義在a.js所在的模塊中碱璃,外面的模塊獲取不到這個Symbol弄痹,也不可能再創(chuàng)建一個一模一樣的Symbol出來(因?yàn)镾ymbol是唯一的),因此這個PASSWORD的Symbol只能被限制在a.js內(nèi)部使用嵌器,所以使用它來定義的類屬性是沒有辦法被模塊外訪問到的肛真,達(dá)到了一個私有化的效果。
- 場景四:注冊和獲取全局Symbol
通常情況下爽航,我們在一個瀏覽器窗口中(window)蚓让,使用Symbol()函數(shù)來定義和Symbol實(shí)例就足夠了乾忱。但是,如果你的應(yīng)用涉及到多個window(最典型的就是頁面中使用了<iframe>)凭疮,并需要這些window中使用的某些Symbol是同一個饭耳,那就不能使用Symbol()函數(shù)了,因?yàn)橛盟诓煌瑆indow中創(chuàng)建的Symbol實(shí)例總是唯一的执解,而我們需要的是在所有這些window環(huán)境下保持一個共享的Symbol寞肖。這種情況下,我們就需要使用另一個API來創(chuàng)建或獲取Symbol衰腌,那就是Symbol.for()新蟆,它可以注冊或獲取一個window間全局的Symbol實(shí)例
let gs1 = Symbol.for('global_symbol_1') //注冊一個全局Symbol
let gs2 = Symbol.for('global_symbol_1') //獲取全局Symbol
gs1 === gs2 // true
4. JavaScript中的變量在內(nèi)存中的具體存儲形式
棧內(nèi)存和堆內(nèi)存
JavaScript中的變量分為基本類型和引用類型
基本類型是保存在棧內(nèi)存中的簡單數(shù)據(jù)段,它們的值都有固定的大小右蕊,保存在椙淼荆空間,通過按值訪問
引用類型是保存在堆內(nèi)存中的對象饶囚,值大小不固定帕翻,棧內(nèi)存中存放的該對象的訪問地址指向堆內(nèi)存中的對象,JavaScript不允許直接訪問堆內(nèi)存中的位置萝风,因此操作對象時嘀掸,實(shí)際操作對象的引用
let a1 = 0; // 棧內(nèi)存
let a2 = "this is string" // 棧內(nèi)存
let a3 = null; // 棧內(nèi)存
let b = { x: 10 }; // 變量b存在于棧中,{ x: 10 }作為對象存在于堆中
let c = [1, 2, 3]; // 變量c存在于棧中规惰,[1, 2, 3]作為對象存在于堆中
棧內(nèi)存 | 堆內(nèi)存 |
---|---|
存儲基礎(chǔ)數(shù)據(jù)類型 | 存儲引用數(shù)據(jù)類型 |
按值訪問 | 按引用訪問 |
存儲的值大小固定 | 存儲的值大小不定睬塌,可動態(tài)調(diào)整 |
由系統(tǒng)自動分配內(nèi)存空間 | 由代碼進(jìn)行指定分配 |
空間小,運(yùn)行效率高 | 空間大歇万,運(yùn)行效率相對較低 |
先進(jìn)后出揩晴,后進(jìn)先出 | 無序存儲,可根據(jù)引用直接獲取 |
5. 基本類型對應(yīng)的內(nèi)置對象贪磺,以及他們之間的裝箱拆箱操作
基本類型的內(nèi)置對象有String()
硫兰、Number()
、Boolean()
缘挽、Symbol()
引用類型的內(nèi)置對象有RegExp()
瞄崇、Date()
、Array()
壕曼、Object()
、Function()
等浊、Error()
腮郊、
裝箱操作:隱式轉(zhuǎn)換 值類型 =》 對象類型
拆箱操作:顯式轉(zhuǎn)換 對象類型 =》 值類型
裝箱,就是把基本類型轉(zhuǎn)變?yōu)閷?yīng)的對象筹燕。裝箱分為隱式和顯示轧飞。
隱式裝箱
每當(dāng)讀取一個基本類型的值時衅鹿,后臺會創(chuàng)建一個該基本類型所對應(yīng)的對象。在這個基本類型上調(diào)用方法过咬,其實(shí)是在這個基本類型對象上調(diào)用方法大渤。這個基本類型的對象是臨時的,它只存在于方法調(diào)用那一行代碼執(zhí)行的瞬間掸绞,執(zhí)行方法后立刻被銷毀泵三。
num.toFixed(2); // '123.00'
//上方代碼在后臺的真正步驟為
var c = new Number(123);//創(chuàng)建一個 Number 類型的實(shí)例。
c.toFixed(2);//在實(shí)例上調(diào)用方法衔掸。
c = null;//銷毀實(shí)例
顯式裝箱
通過內(nèi)置對象 Boolean烫幕、Object、String 等可以對基本類型進(jìn)行顯示裝箱敞映。
var obj = new String('123');
拆箱较曼。拆箱與裝箱相反,把對象轉(zhuǎn)變?yōu)榛绢愋偷闹嫡裨浮2鹣溥^程內(nèi)部調(diào)用了抽象操作 ToPrimitive 捷犹。該操作接受兩個參數(shù),第一個參數(shù)是要轉(zhuǎn)變的對象冕末,第二個參數(shù) PreferredType 是對象被期待轉(zhuǎn)成的類型萍歉。第二個參數(shù)不是必須的,默認(rèn)該參數(shù)為 number栓霜,即對象被期待轉(zhuǎn)為數(shù)字類型翠桦。有些操作如 String(obj) 會傳入 PreferredType 參數(shù)。有些操作如 obj + " " 不會傳入 PreferredType
具體轉(zhuǎn)換過程是這樣的胳蛮。默認(rèn)情況下销凑,ToPrimitive 先檢查對象是否有 valueOf 方法,如果有則再檢查 valueOf 方法是否有基本類型的返回值仅炊。如果沒有 valueOf 方法或 valueOf 方法沒有返回值斗幼,則調(diào)用 toString 方法。如果 toString 方法也沒有返回值抚垄,產(chǎn)生 TypeError 錯誤蜕窿。
PreferredType 影響 valueOf 與 toString 的調(diào)用順序。如果 PreferrenType 的值為 string呆馁。則先調(diào)用 toString ,再調(diào)用 valueOf桐经。
var obj = {
valueOf : () => {console.log("valueOf"); return []},
toString : () => {console.log("toString"); return []}
}
String(obj)
// toString
// valueOf
// Uncaught TypeError: Cannot convert object to primitive value
obj+' '
//valueOf
//toString
// Uncaught TypeError: Cannot convert object to primitive value
Number(obj)
//valueOf
//toString
// Uncaught TypeError: Cannot convert object to primitive value
6. 理解值類型和引用類型
基本類型的內(nèi)置對象有String()
、Number()
浙滤、Boolean()
阴挣、Symbol()
引用類型的內(nèi)置對象有RegExp()
、Date()
纺腊、Array()
畔咧、Object()
茎芭、Function()
、Error()
誓沸、
值類型
1梅桩、占用空間固定,保存在棧中(當(dāng)一個方法執(zhí)行時拜隧,每個方法都會建立自己的內(nèi)存棧宿百,在這個方法內(nèi)定義的變量將會逐個放入這塊棧內(nèi)存里,隨著方法的執(zhí)行結(jié)束虹蓄,這個方法的內(nèi)存棧也將自然銷毀了犀呼。因此,所有在方法中定義的變量都是放在棧內(nèi)存中的薇组;棧中存儲的是基礎(chǔ)變量以及一些對象的引用變量外臂,基礎(chǔ)變量的值是存儲在棧中,而引用變量存儲在棧中的是指向堆中的數(shù)組或者對象的地址律胀,這就是為何修改引用類型總會影響到其他指向這個地址的引用變量宋光。)
2、保存與復(fù)制的是值本身
3炭菌、使用typeof檢測數(shù)據(jù)的類型
4罪佳、基本類型數(shù)據(jù)是值類型引用類型
1、占用空間不固定黑低,保存在堆中(當(dāng)我們在程序中創(chuàng)建一個對象時赘艳,這個對象將被保存到運(yùn)行時數(shù)據(jù)區(qū)中,以便反復(fù)利用(因?yàn)閷ο蟮膭?chuàng)建成本通常較大)克握,這個運(yùn)行時數(shù)據(jù)區(qū)就是堆內(nèi)存蕾管。堆內(nèi)存中的對象不會隨方法的結(jié)束而銷毀,即使方法結(jié)束后菩暗,這個對象還可能被另一個引用變量所引用(方法的參數(shù)傳遞時很常見)掰曾,則這個對象依然不會被銷毀,只有當(dāng)一個對象沒有任何引用變量引用它時停团,系統(tǒng)的垃圾回收機(jī)制才會在核實(shí)的時候回收它旷坦。)
2、保存與復(fù)制的是指向?qū)ο蟮囊粋€指針
3佑稠、使用instanceof檢測數(shù)據(jù)類型
4秒梅、使用new()方法構(gòu)造出的對象是引用型
7. null和undefined的區(qū)別
null == undefined // true
null === undefined // false
!!null // false
!!undefined // false
Number(null) //0
Number(undefined) //NaN
/*null更多表示引用語義, 它表示一個值被定義了,定義為“空值”舌胶。
undefined更多表示值語義番电,它表示根本不存在定義。
所以設(shè)置一個值為null是合理的辆琅,但是設(shè)置一個值為undefined就不合理漱办。*/
typeof null // object
typeof undefined // undefined
8. 至少可以說出三種判斷JavaScript數(shù)據(jù)類型的方式,以及他們的優(yōu)缺點(diǎn)婉烟,如何準(zhǔn)確的判斷數(shù)組類型
判斷數(shù)據(jù)類型的方法一般可以通過:typeof娩井、instanceof、constructor似袁、Object.prototype.toString.call();四種常用方法
- typeof
typeof 返回一個表示數(shù)據(jù)類型的字符串洞辣,返回結(jié)果包括:number、boolean昙衅、string扬霜、object、undefined而涉、function著瓶、Symbol6種數(shù)據(jù)類型。
對于引用類型啼县,返回的都是object材原,其實(shí)返回object也沒有錯,因?yàn)樗袑ο蟮脑玩溩罱K都指向了Object,Object是所有對象的祖宗
季眷。 但當(dāng)我們需要知道某個對象的具體類型時余蟹,typeof 就顯得有些力不從心了。
注意:typeof null也是返回object
- instanceof
判斷對象和構(gòu)造函數(shù)在原型鏈上是否有關(guān)系子刮,如果有關(guān)系威酒,返回真,否則返回假.
function Aaa(){
}
var a1 = new Aaa();
console.log( a1 instanceof Aaa);
//true 判斷a1和Aaa是否在同一個原型鏈上挺峡,是的話返回真葵孤,否則返回假
var arr = [];
console.log( arr instanceof Aaa);//false
var str = 'hello';
alert(str instanceof String);//false
var bool = true;
alert(bool instanceof Boolean);//false
var num = 123;
alert(num instanceof Number);//false
var nul = null;
alert(nul instanceof Object);//false
var und = undefined;
alert(und instanceof Object);//false
var oDate = new Date();
alert(oDate instanceof Date);//true
var json = {};
alert(json instanceof Object);//true
var arr = [];
alert(arr instanceof Array);//true
var reg = /a/;
alert(reg instanceof RegExp);//true
var fun = function(){};
alert(fun instanceof Function);//true
var error = new Error();
alert(error instanceof Error);//true
從上面的運(yùn)行結(jié)果我們可以看到,基本數(shù)據(jù)類型是沒有檢測出他們的類型沙郭,但是我們使用下面的方式創(chuàng)建num佛呻、str、boolean病线,是可以檢測出類型的:
var num = new Number(123);
var str = new String('abcdef');
var boolean = new Boolean(true);
console.log(num instanceof Number)//true
console.log(str instanceof String)//true
- constructor:查看對象對應(yīng)的構(gòu)造函數(shù)
constructor 在其對應(yīng)對象的原型下面吓著,是自動生成的。當(dāng)我們寫一個構(gòu)造函數(shù)的時候送挑,程序會自動添加:構(gòu)造函數(shù)名.prototype.constructor = 構(gòu)造函數(shù)名
function Aaa(){
}
//Aaa.prototype.constructor = Aaa; //每一個函數(shù)都會有的绑莺,都是自動生成的
判斷數(shù)據(jù)類型的方法
var str = 'hello';
alert(str.constructor == String);//true
var bool = true;
alert(bool.constructor == Boolean);//true
var num = 123;
alert(num.constructor ==Number);//true
// var nul = null;
// alert(nul.constructor == Object);//報(bào)錯
//var und = undefined;
//alert(und.constructor == Object);//報(bào)錯
var oDate = new Date();
alert(oDate.constructor == Date);//true
var json = {};
alert(json.constructor == Object);//true
var arr = [];
alert(arr.constructor == Array);//true
var reg = /a/;
alert(reg.constructor == RegExp);//true
var fun = function(){};
alert(fun.constructor ==Function);//true
var error = new Error();
alert(error.constructor == Error);//true
從上面的測試中我們可以看到,undefined和null是不能夠判斷出類型的惕耕,并且會報(bào)錯纺裁。因?yàn)閚ull和undefined是無效的對象,因此是不會有constructor存在的
同時我們也需要注意到的是:使用constructor是不保險的,因?yàn)閏onstructor屬性是可以被修改的欺缘,會導(dǎo)致檢測出的結(jié)果不正確
備注:使用Object.create()創(chuàng)建的js對象栋豫,沒有constructor
- Object.prototype.toString(可以說不管是什么類型,它都可以立即判斷出)
toString是Object原型對象上的一個方法谚殊,該方法默認(rèn)返回其調(diào)用者的具體類型丧鸯,更嚴(yán)格的講,是 toString運(yùn)行時this指向的對象類型, 返回的類型
格式為[object xxx],xxx是具體的數(shù)據(jù)類型嫩絮,其中包括:
String,Number,Boolean,Undefined,Null,Function,Date,Array,RegExp,Error,HTMLDocument,... 基本上所有對象的類型都可以通過這個方法獲取到丛肢。
var str = 'hello';
console.log(Object.prototype.toString.call(str));//[object String]
var bool = true;
console.log(Object.prototype.toString.call(bool))//[object Boolean]
var num = 123;
console.log(Object.prototype.toString.call(num));//[object Number]
var nul = null;
console.log(Object.prototype.toString.call(nul));//[object Null]
var und = undefined;
console.log(Object.prototype.toString.call(und));//[object Undefined]
var oDate = new Date();
console.log(Object.prototype.toString.call(oDate));//[object Date]
var json = {};
console.log(Object.prototype.toString.call(json));//[object Object]
var arr = [];
console.log(Object.prototype.toString.call(arr));//[object Array]
var reg = /a/;
console.log(Object.prototype.toString.call(reg));//[object RegExp]
var fun = function(){};
console.log(Object.prototype.toString.call(fun));//[object Function]
var error = new Error();
console.log(Object.prototype.toString.call(error));//[object Error]
類型 | typeof | instanceof | constructor | Object.prototype.toString.call |
---|---|---|---|---|
優(yōu)點(diǎn) | 使用簡單 | 能檢測出引用類型 | 基本能檢測所有的類型(除了null和undefined) | 檢測出所有類型 |
缺點(diǎn) | 只能檢測出基本類型(出null) | 能檢測出基本類型,且不能跨iframe | constructor易被修改剿干,也不能跨iframe IE6下蜂怎,undefined和null均為Object |
例:跨頁面判斷是否是數(shù)組
window.onload = function(){
var oF = document.createElement('iframe');
document.body.appendChild( oF );
var ifArray = window.frames[0].Array;
var arr = new ifArray();
//alert( arr.constructor == Array ); //false
//alert( arr instanceof Array ); //false
alert( Object.prototype.toString.call(arr) == '[object Array]' ); //true
};
9. 可能發(fā)生隱式類型轉(zhuǎn)換的場景以及轉(zhuǎn)換原則,應(yīng)如何避免或巧妙應(yīng)用
js數(shù)據(jù)類型隱式轉(zhuǎn)換主要分為三種情況
1.轉(zhuǎn)換為string
2.轉(zhuǎn)換為number
3.轉(zhuǎn)換為boolean
原始值 | 轉(zhuǎn)換目標(biāo) | 結(jié)果 |
---|---|---|
number | 布爾值 | 除了0置尔,-0杠步,NaN都為true |
string | 布爾值 | 除了空字符串都為true |
defined、null | 布爾值 | false |
引用類型 | 布爾值 | false |
number | 字符串 | 5=>'5' |
Boolean撰洗、函數(shù)篮愉、Symbol | 字符串 | 'true' |
數(shù)組 | 字符串 | [1,2]=>'1,2' |
對象 | 字符串 | '[object object]' |
string | 數(shù)字 | '1'=>1,'a'=>NaN |
數(shù)組 | 數(shù)字 | 空數(shù)組為0,存在一個元素且為數(shù)字轉(zhuǎn)數(shù)字差导,其他情況NaN |
null | 數(shù)字 | 0 |
除了數(shù)組的引用類型 | 數(shù)字 | NaN |
Symbol | 數(shù)字 | 拋錯 |
隱式類型轉(zhuǎn)換试躏。Javascript默認(rèn)自動轉(zhuǎn)換,沒有任何警告设褐,隱式類型轉(zhuǎn)換常見場景
- 自動轉(zhuǎn)換Boolean
例如if語句或者其他需要Boolean的地方
if (表達(dá)式){}
- 在非 Numeber 類型進(jìn)行數(shù)學(xué)運(yùn)算符 - * / 時颠蕴,會先將非 Number 轉(zhuǎn)換成 Number 類型。
+
運(yùn)算符要考慮字符串的情況助析,在操作數(shù)中存在字符串時犀被,優(yōu)先轉(zhuǎn)換成字符串
+
運(yùn)算符其中一個操作數(shù)是字符串的話,會進(jìn)行連接字符串的操作
1+'2' // '12'
+
操作符的執(zhí)行順序是:
當(dāng)一側(cè)操作數(shù)為 String 類型外冀,會優(yōu)先將另一側(cè)轉(zhuǎn)換為字符串類型寡键。
當(dāng)一側(cè)操作數(shù)為 Number 類型,另一側(cè)為原始類型雪隧,則將原始類型轉(zhuǎn)換為 Number 類型西轩。
當(dāng)一側(cè)操作數(shù)為 Number 類型,另一側(cè)為引用類型脑沿,將引用類型和 Number 類型轉(zhuǎn)換成字符串后拼接藕畔。
- 對象。只有在 JavaScript 表達(dá)式或語句中需要用到數(shù)字或字符串時庄拇,對象才被隱式轉(zhuǎn)換注服。
當(dāng)需要將對象轉(zhuǎn)換為數(shù)字時韭邓,需要三個步驟
3*{valueOf:function () { return 5 }} // 15,調(diào)用 valueOf()。如果結(jié)果是原始值(不是一個對象)溶弟,則將其轉(zhuǎn)換為一個數(shù)字女淑。
3*{toString:function () { return 5 }} // 15,否則,調(diào)用 toString() 方法可很。如果結(jié)果是原始值诗力,則將其轉(zhuǎn)換為一個數(shù)字
3*{toString:function () { return {} }} //TypeError: Cannot convert object to primitive value
//否則,拋出一個類型錯誤我抠。
10. 出現(xiàn)小數(shù)精度丟失的原因,JavaScript可以存儲的最大數(shù)字袜茧、最大安全數(shù)字菜拓,JavaScript處理大數(shù)字的方法、避免精度丟失的方法
var x = 0.3 - 0.2; //30美分減去20美分
var y = 0.2 - 0.1; //20美分減去10美分
x == y; // =>false,兩值不相等
x == 0.1; // =>false,真實(shí)值為:0.09999999999999998
y == 0.1; // =>true
這個問題并不只是在Javascript中才會出現(xiàn)笛厦,任何使用二進(jìn)制浮點(diǎn)數(shù)的編程語言都會有這個問題纳鼎,只不過在 C++/C#/Java 這些語言中已經(jīng)封裝好了方法來避免精度的問題,而 JavaScript 是一門弱類型的語言裳凸,從設(shè)計(jì)思想上就沒有對浮點(diǎn)數(shù)有個嚴(yán)格的數(shù)據(jù)類型贱鄙,所以精度誤差的問題就顯得格外突出
解決辦法
//加法
Number.prototype.add = function(arg) {
var r1, r2, m;
try {
r1 = this.toString().split(".")[1].length;
} catch (e) {
r1 = 0;
}
try {
r2 = arg.toString().split(".")[1].length;
} catch (e) {
r2 = 0;
}
m = Math.pow(10, Math.max(r1, r2));
return (this * m + arg * m) / m;
};
//減法
Number.prototype.sub = function(arg) {
return this.add(-arg);
};
//乘法
Number.prototype.mul = function(arg) {
var m = 0,
s1 = this.toString(),
s2 = arg.toString();
try {
m += s1.split(".")[1].length;
} catch (e) {}
try {
m += s2.split(".")[1].length;
} catch (e) {}
return (
(Number(s1.replace(".", "")) * Number(s2.replace(".", ""))) /
Math.pow(10, m)
);
};
//除法
Number.prototype.div = function(arg) {
var t1 = 0,
t2 = 0,
r1,
r2;
try {
t1 = this.toString().split(".")[1].length;
} catch (e) {}
try {
t2 = arg.toString().split(".")[1].length;
} catch (e) {}
with (Math) {
r1 = Number(this.toString().replace(".", ""));
r2 = Number(arg.toString().replace(".", ""));
return (r1 / r2) * pow(10, t2 - t1);
}
};
參考鏈接:https://blog.csdn.net/Donspeng/java/article/details/76019815
http://www.reibang.com/p/f40a77bbd74e
http://www.reibang.com/p/80bb5a01857a
https://blog.csdn.net/xieamy/java/article/details/89892451
http://www.reibang.com/p/d66cf6f711a1
https://blog.csdn.net/weixin_43618932/java/article/details/103109718
https://juejin.im/post/5cda9178f265da0379419ad1