js中有七種數(shù)據(jù)類型,包括基本數(shù)據(jù)類型 Number托慨、String葵孤、Boolean担钮、Undefined、Null尤仍、Symbol(ES6 新增,創(chuàng)建后獨(dú)一無(wú)二且不可變的數(shù)據(jù)類型)箫津,一種復(fù)雜數(shù)據(jù)類型( Object )。
由于js中的變量是松散類型多的宰啦,所以它提供了一種檢測(cè)當(dāng)前變量的數(shù)據(jù)類型的方法苏遥,也就是 typeof 關(guān)鍵字。
typeof 123 // Number
typeof 'abc' // String
typeof true //Boolean
typeof undefined //Undefined
typeof null //Object
typeof {} //Object
typeof [] //Object
let a = function() {
console.log(1)
}
typeof a //function
let s = Symbol();
typeof s //symbol
null類型進(jìn)行typeof操作符后赡模,結(jié)果是object田炭,原因在于,null類型被當(dāng)做一個(gè)空對(duì)象引用纺裁。
1.Number
Number類型包含整數(shù)和浮點(diǎn)數(shù)兩種值诫肠。
NaN:非數(shù)字類型。特點(diǎn):涉及到的任何關(guān)于NaN的操作欺缘,都會(huì)返回NaN栋豫;NaN不等于自身懦鼠。
isNaN()函數(shù)用于檢查其參數(shù)是否是非數(shù)字值讨阻。
isNaN(123) //false
isNaN("hello") //true
2.String
字符串有l(wèi)ength屬性。
字符串轉(zhuǎn)換:
String():適合于任何數(shù)據(jù)類型(null,undefined轉(zhuǎn)換后為null和undefined)嘹叫;
toString()方法:括號(hào)中的可以寫一個(gè)數(shù)字嫩絮,代表進(jìn)制丛肢,對(duì)應(yīng)進(jìn)制字符串围肥,null、defined沒(méi)有toString()方法蜂怎。
3.Boolean
該類型只有兩個(gè)值穆刻,true和false。
4.Undefined
只有一個(gè)值杠步,即undefined值氢伟。使用var聲明了變量,但未給變量初始化值幽歼,那么這個(gè)變量的值就是undefined朵锣。
5.Null
null類型被看做空對(duì)象指針,前文的null類型也是空的對(duì)象引用甸私。
6.Symbol
Symbol是ES6新增的原始數(shù)據(jù)類型诚些,是為了解決在對(duì)象中對(duì)屬性名濫用而導(dǎo)致的沖突問(wèn)題。
ps:既然是數(shù)據(jù)類型皇型,不是對(duì)象诬烹,那么就不能用new命令,因此不能添加屬性犀被。
let a = Symbol('a');
console.log(a); //Symbol(a)
console.log(typeof a) //symbol
簡(jiǎn)單來(lái)說(shuō):一旦聲明一個(gè)變量為symbol類型椅您,說(shuō)明這個(gè)變量是唯一的外冀,獨(dú)一無(wú)二的寡键,覆蓋不了的。
let a = Symbol('abc');
let b = Symbol('abc');
let c = 'abc';
let d = 'abc';
console.log(a === b) //false
console.log(c === d) //true
現(xiàn)在雪隧,在對(duì)象的屬性名有兩種類型西轩,一個(gè)是以字符串的形式,另一個(gè)是以Symbol的形式脑沿。
若以symbol的形式去寫藕畔,那么就要按照規(guī)范去寫,加上中括號(hào)[]庄拇,來(lái)表明使用了symbol類型注服,獲取時(shí)而不是按照字符串類型的屬性名去獲取,而以中括號(hào)獲取措近。
let name = Symbol();
let obj = {
[name]: 'black',
age: 25,
name: 'red'
}
console.log(obj) //{age: 25,name: "red",Symbol(): "black"}
通過(guò)例子可知:獲取對(duì)象時(shí)溶弟,得到是兩個(gè)不一樣的name屬性名,說(shuō)明symbol和字符串時(shí)兩種不一樣的值瞭郑,獲取方式也不一樣辜御,按照點(diǎn)獲取的是字符串,中括號(hào)獲取的是symbol類型的值屈张。
關(guān)于在對(duì)象聲明時(shí)對(duì)symbol類型的寫法有三種:
let sym = Symbol();
//第一種寫法:
let a = {};
a[sym] = 'hello';
console.log(a); //{Symbol(): "hello"}
//第二種寫法:
let a = {
[sym]: 'hello'
}
console.log(a); //{Symbol(): "hello"}
//第三種寫法:
let a = {};
Object.defineProperty(a, sym, {value: "hello"});
console.log(a);
實(shí)例:
const shapeType = {
triangle: Symbol(),
rectangle: Symbol(),
};
function getArea(shape, options) {
let area = 0;
switch (shape) {
case shapeType.triangle:
area = .5 * options.width * options.height;
break;
case shapeType.rectangle:
area = options.width * options.height;
break;
}
return area;
}
let a = getArea(shapeType.triangle, { width: 100, height: 100 });
let b = getArea(shapeType.rectangle, { width: 100, height: 100 });
console.log(a) // 5000
console.log(b) // 10000
Symbol方法:
Object.getOwnPropertySymbols()返回一個(gè)數(shù)組擒权,成員是當(dāng)前對(duì)象的所有用作屬性名的Symbol值袱巨。
symbol在對(duì)象上作為一個(gè)屬性名,不會(huì)被循環(huán)的方法所識(shí)別碳抄,不會(huì)出現(xiàn)在for...in愉老、for...of循環(huán)中,不會(huì)被Object.keys()剖效、Object.getOwnPropertyNames()俺夕、JSON.stringify()返回,所以它有自己獲取symbol值的方法贱鄙。
let name = Symbol('name');
let age = Symbol('age')
let obj = {
[name]: 'peter',
[age]: 25
}
let a = Object.getOwnPropertySymbols(obj)
console.log(a) // [Symbol(name), Symbol(age)]
Reflect.ownKeys() 返回所有類型的鍵名劝贸,包括常規(guī)鍵名和 Symbol 鍵名
let name = Symbol('name');
let obj = {
[name]: 'peter',
age: 25,
enum: 2
}
console.log(Reflect.ownKeys(obj)) // ["age", "enum", Symbol(name)]
Symbol.for() 接受一個(gè)字符串作為參數(shù),然后搜索有沒(méi)有以該參數(shù)作為名稱的 Symbol 值逗宁。如果有映九,就返回這個(gè) Symbol 值,否則就新建并返回一個(gè)以該字符串為名稱的 Symbol 值瞎颗。
這個(gè)方法就是重新使用已有symbol的值件甥,在遍歷判斷時(shí)常用 。
let a = Symbol.for('abc');
let b = Symbol.for('abc');
let c = Symbol.for('ab');
console.log(a === b) // true
let a = Symbol.for('abc')
let b = Symbol('abc')
console.log(a) // Symbol(abc)
console.log(a === b) // false
由此可知:a雖然用Symbol.for聲明了symbol類型哼拔,但是卻和symbol聲明不一樣引有,說(shuō)明兩者不是同一個(gè)值。
Symbol函數(shù)可以接受一個(gè)字符串作為參數(shù)倦逐,表示對(duì)Symbol實(shí)例的描述譬正,主要是為了在控制臺(tái)顯示,或者轉(zhuǎn)為字符串時(shí)檬姥,比較容易區(qū)分曾我。
let s1 = Symbol('foo');
let s2 = Symbol('bar');
s1 //Symbol(foo)
s2 //Symbol(bar)
s1.toString(); //"Symbol(foo)"
s2.toString(); //"Symbol(bar)"
上面代碼中,s1和s2是兩個(gè)Symbol值健民。如果不加參數(shù)抒巢,他們?cè)诳刂婆_(tái)輸出都是Symbol(),不利于區(qū)分秉犹。有了參數(shù)以后蛉谜,就等于為它們加上了描述,輸出的時(shí)候就能夠分清崇堵,到底是哪一個(gè)值型诚。
如果Symbol的參數(shù)是一個(gè)對(duì)象,就會(huì)調(diào)用該對(duì)象的toString方法筑辨,將其轉(zhuǎn)為字符串俺驶,然后生成一個(gè)Symbol。
const obj = {
toString() {
return 'abc'
}
}
const sym = Symbol(obj);
sym //Symbol(abc)
注意,Symbol函數(shù)的參數(shù)只是表示對(duì)當(dāng)前Symbol值的描述暮现,因此相同參數(shù)的Symbol函數(shù)的返回值是不相等的还绘。
// 沒(méi)有參數(shù)的情況
let s1 = Symbol();
let s2 = Symbol();
s1 === s2 //false
//有參數(shù)的情況
let s1 = Symbol('foo');
let s2 = Symbol('foo');
s1 === s2 //false
上面代碼中,s1和s2都是Symbol函數(shù)的返回值栖袋,而且參數(shù)相同拍顷,但是它們是不相等的。
Symbol 值不能與其他類型的值進(jìn)行運(yùn)算塘幅,會(huì)報(bào)錯(cuò)昔案。
let sym = Symbol('My symbol');
"you symbol is"+sym
// Uncaught TypeError: Cannot convert a Symbol value to a string
`your symbol is ${sym}`
// TypeError: can't convert symbol to string
但是,Symbol 值可以顯式轉(zhuǎn)為字符串电媳。
let sym = Symbol('My symbol');
String(sym) // 'Symbol(My symbol)'
sym.toString() // 'Symbol(My symbol)'
另外踏揣,Symbol值可以轉(zhuǎn)變?yōu)椴紶栔担遣荒苻D(zhuǎn)為數(shù)值匾乓。
let sym = Symbol();
Boolean(sym) //true
!sym //false
if(sym){
//...
}
Number(sym) //TypeError
sym+2 //TypeError
7.Object
js中對(duì)象是一組屬性與方法的集合捞稿。這里就要說(shuō)到引用類型了,引用類型是一種數(shù)據(jù)結(jié)構(gòu)拼缝,用于將數(shù)據(jù)和功能組織在一起娱局。引用類型有時(shí)候也被稱為對(duì)象定義,因?yàn)樗鼈兠枋龅氖且活悓?duì)象所具有的屬性和方法咧七。
三大引用類型:
1.Object類型
我們看到的大多數(shù)類型值都是Object類型的實(shí)例衰齐,創(chuàng)建Object實(shí)例的方式有兩種:
第一種是使用new操作符后跟Object構(gòu)造函數(shù),如下所示:
var person = new Object();
person.name = "托尼老師";
person.age = 24;
第二種方式是使用對(duì)象字面量表示法继阻,如下所示:
var person = {
name: '托尼老師',
age: 24
}
2.Array類型
數(shù)組的每一項(xiàng)都可以用來(lái)保存任何類型的數(shù)據(jù)耻涛,也就是說(shuō),可以用數(shù)組的第一個(gè)位置來(lái)保存字符串穴翩,第二個(gè)位置保存數(shù)值犬第,第三個(gè)位置保存對(duì)象...另外锦积,數(shù)組的大小是可以動(dòng)態(tài)調(diào)整的芒帕。
創(chuàng)建數(shù)組的基本方式有兩種:
第一種是使用Array構(gòu)造函數(shù),如下所示:
var colors = new Array("red","blue","yellow");
第二種是使用數(shù)組字面量表示方法丰介,如下所示:
var colors = ["red","blue","yellow"];
3.function類型
每個(gè)函數(shù)都是Function類型的實(shí)例背蟆,而且都與其他引用類型一樣具有屬性和方法。函數(shù)通常是使用函數(shù)聲明語(yǔ)法定義的哮幢,如下所示:
function sum(num1,num2){
return num1 + num2;
}
這和使用函數(shù)表達(dá)式定義函數(shù)的方式相差無(wú)幾带膀。
var sun = function(){
return sum1 + sum2;
}
也就是說(shuō),js按照存儲(chǔ)方式分為值類型和引用類型橙垢。他們計(jì)算有什么區(qū)別呢垛叨?
題目1:
var a = 100;
var b = a;
a =200;
console.log(b); //100
題目2:
var a = {age : 20};
var b = a;
b.age = 21;
console.log(a.age); //21
題目一是簡(jiǎn)單的值類型,在從一個(gè)變量向另一個(gè)變量賦值基本類型時(shí)柜某,會(huì)在該變量上創(chuàng)建一個(gè)新值嗽元,然后再把該值復(fù)制到為新變量分配的位置上敛纲。
此時(shí),a中保存的值為100剂癌,當(dāng)使用a來(lái)初始化b時(shí)淤翔,b中保存的值也為100,但b中的100與a中的是完全獨(dú)立的佩谷,該值只是a中的值的一個(gè)副本旁壮,此后,這兩個(gè)變量可以參加任何操作而不受影響谐檀。就是說(shuō)基本類型在賦值操作后抡谐,兩個(gè)類型是相互不受影響的。
題目2是引用類型桐猬,當(dāng)從一個(gè)變量向另一個(gè)變量賦值引用類型的值時(shí)童叠,同樣也會(huì)將存儲(chǔ)在變量中的對(duì)象的值賦值一份放到為新變量分配的空間中。
這時(shí)保存在變量中的對(duì)象是堆內(nèi)存中的地址课幕,所以厦坛,與簡(jiǎn)單賦值不同,這個(gè)值的副本實(shí)際上是一個(gè)指針乍惊,而這個(gè)指針指向存儲(chǔ)在堆內(nèi)存的一個(gè)對(duì)象杜秸。那么賦值操作后,兩個(gè)變量都保存了同一對(duì)象地址润绎,則這兩個(gè)變量指向了同一個(gè)對(duì)象撬碟,因此,改變其中任何一個(gè)變量莉撇,都會(huì)相互影響呢蛤。
因此,引用類型的賦值其實(shí)是對(duì)象保存在棧區(qū)地址指針的賦值棍郎,所以兩個(gè)變量指向同一個(gè)對(duì)象其障,任何的操作都會(huì)相互影響。