## 一、數據類型
JS分兩種數據類型:
> **基本數據類型**:**Number、String、Boolean、Null、?Undefined、Symbol(ES6),**這些類型可以直接操作保存在變量中的實際值。
>
>**引用數據類型**:**Object(在JS中除了基**本**數據類型以外的都是對象,數據是對象,函數是對象,正則表達式是對象)**
## 1、基本數據類型(六種)存放在棧中
>基本數據類型是指存放在**棧**中的**簡單數據段,數據大小確定,內存空間大小可以分配,**它們是直接按值存放的,所以可以直接**按值訪問**
* 1、`Number`數值類型
`Number`類型包含整數和浮點數(浮點數數值必須包含一個小數點,且小數點后面至少有一個數字)兩種值
>注意:在js中浮點數的精度是17位,計算是二進制的計算數 據,所以得到的不是整數
```
var num1 = 0.1;
var num2 = 0.2;
console.log(num1 + num2); //0.30000000000000004
```
`NaN`:非數字類型,屬于數值型基本數據類型
>特點:
1):設計任何的NaN操縱都會返回NaN
`console.log('ab'/10); ` // NaN
2) NaN不等于自身。
`console.log(NaN == NaN);// false;`
判斷是否是`Number`類型
>1、`isNaN`:判斷是否是一個非數字類型,傳入的非數字類型,返回`true`,否則返回`false`
>注意:傳入的參數首先會被轉化為數值,如果參數類型為對象類型,先調用`valueOf()`方法,再確定該方法返回的值是否可以轉換為數值類型,如果不能,再調用`toString()`方法,再確定返回值
2、`typeof`
`console.log(typeof 12)` //Number
數值類型的轉換:
`Number()`:可以用于任何的數據類型
`parseInt`:提取 整數數值
`paseFloat`:提取浮點數值
* 2、`String` 字符串類型
>特點:
1、字符串的單引號和雙引號作用效果一樣
2、字符串有`length`屬性,可以取得字符串的長度
3、字符串的值是不可變的,所以很多的字符串的`api`不會改變原字符串值
>字符串轉換:
`String()`:適用于任何的數據類型(null -> null undefined -> undefined)
`toString()`:`null`和`undefined`沒有這個功能
`console.log(null.toString()); //error 報錯`
* 3、`Boolean` 布爾類型
該類型只有兩個值:`true`、`false`
```
轉換為`boolean`: `Boolean()`
Boolean(undefined):false
Boolean(null):false
Boolean(非空對象包括空數組[]和空對象{}):true
Boolean(非0): true || Boolean(0和NaN):false
Boolean(非空包括空格字符串):true || Boolean(''):false
[注意]true不一定等于1,false也不一定等于0
```
出現場景:
(1)條件語句導致執行的隱士類轉換
(2)字面量或變量定義
```
類型轉換:
Number(true): 1 || Number(false) : 0
String(true):'true' ?|| String(false):'false'
```
* 4、`Null` 空對象指針類型
如果定了一個對象,初始化可以為null,因為null的基本類型是`Null`,在`if`語句中默認轉化為`false`,在和數值計算默認為`0`
出現場景:對象不存在
```
類型轉換:
Booleam(null) false
Number(num) 0
String(null) 'null'
```
`Number(null) // 0`
* 5、`Undefined`
申明了變量但是沒有初始化,默認為`undefined`,在`if`語句中默認轉化為`false`,
>`undefined`:表示‘缺少值’,就是應該有一個值,但是沒有定義,以下用法是典型的出現`undefined`情況
(1)變量被申明,等于`undefined`
(2)調用函數時,應該提供的參數沒有提供,該參數等于`undefined`
(3)對象沒有賦值的屬性,該屬性值為`undefined`
(4)函數沒有返回值,默認返回`undefined`
```
類型轉換:
Boolean(undefined): ?false
Number(undefined): ?NaN
String(undefined): 'undefined'
```
* 6、`Symbol`
`ES6`新增的一個基本數據類型,表示唯一性
```
let id1 = Symbol('id');
let id2 = Symbol('id');
console.log(id1 == id2); //false
```
`Symbol`屬性類型不支持`for...in `和`Object.keys()`
```
let id = Symbol("id");
let obj = {
[id]:'symbol'
};
for(let option in obj){
console.log(obj[option]); //空
}
```
但是也能有方法去訪問:`Object.getOwnPropertySymbols`
方法會返回一個數組,成員是當前對象的所有用作屬性名的 Symbol 值。
```
console.log(Object.getOwnPropertySymbols(obj))
// [?Symbol(c)?]
```
* 介紹兩個`Symbol.for` 和 `Symbol.keyFor`
(1)、`Symbol.for` :方法根據給到的鍵`key`來運行時的`symbol`注冊表中找到對應的`symbol`,如果找到了,則返回它,否則新增一個與該鍵關聯的`symbol`,并放入全局的`symbol`,這個Symbol值可以是被二次用到的
返回值:
返回由給定的 key 找到的 symbol,否則就是返回新創建的 symbol。
```
Symbol.for("foo"); // 創建一個 symbol 并放入 symbol 注冊表中,鍵為 "foo"
Symbol.for("foo"); // 從 symbol 注冊表中讀取鍵為"foo"的 symbol
Symbol.for("bar") === Symbol.for("bar"); // true,證明了上面說的
Symbol("bar") === Symbol("bar"); // false,Symbol() 函數每次都會返回新的一個 symbol
為了防止沖突,最好給你要放入 symbol 注冊表中的 symbol 帶上鍵前綴。
Symbol.for("mdn.foo");
Symbol.for("mdn.bar");
```
(2)、`Symbol.keyFor`
方法用來獲取 symbol 注冊表中與某個 symbol 關聯的鍵。
```
var globalSym = Symbol.for("foo");
Symbol.keyFor(globalSym); // "foo"
```
## 2、引用數據類型
引用數據類型也叫對象數據類型,包括`function`,`object`,`array`,`date`,`RegExp`等可以可以使用new創建的數據,又叫對象類型,他們是存放在**堆**(heap)**內存**中的數據
特點:
> * 引用類型的值可以改變
> * 引用數據類型可以添加屬性和方法
> * 引用數據類型的賦值是對象引用
> * 引用類型的比較是引用的比較
> * 引用類型是同時保存在棧區中和堆區中的,引用類型的存儲需要在內存的棧區和堆區中共同完成,棧區保存變量標識符和指向堆內存的地址
注意:在引用類型賦值時對象的引用,所以從一個變量向另一個變量賦值引用類型的值時,同樣會將存在在變量中的對象的值賦值一份到新的變量分配的空間,引用類型保存在變量中的時對象在堆存在的地址,所以與基本數據類型的簡單賦值不同,這個值的副本實際上時一個指針,而這個指針指向儲存在堆內存的一個對象,那么賦值操作后,兩個變量都保存了同一個對象的地址,而這個地址都指向同一個對象,因此改變其中任何一個變量,都會影響

在ECMAScript中,Object類型是所有它的實例的基礎
`Object`的每個實例都具有下列的屬性和方法:
* constructor:構造函數
* hasOwnProperty(proertyName)
用于檢查給定的屬性在當前對象實例(而不是實例的原型)中是否存在。
* isPropertyOf(Object)
用于檢查其原型鏈的對象是否存在于指定對象的實例中,是則返回true,否則返回false。
```
var a = {} function Person() {}
var p1 = new Person() // 繼承自原來的原型,但現在已經無法訪問
var Person.prototype = a var p2 = new Person() // 繼承a
console.log(a.isPrototypeOf(p1)) // false a是不是p1的原型
console.log(a.isPrototypeOf(p2)) // true a是不是p2的原型
console.log(Object.prototype.isPrototypeOf(p1)) // true
console.log(Object.prototype.isPrototypeOf(p2)) // true
```
* propertyIsEnumerable(propertyName)
用于檢查給定的屬性是否可以用 for-in 語句進行枚舉。
* toLocaleString()
返回對象的字符串表示,該字符串與執行環境的地區對應。
* toString()
返回對象的字符串表示。
* valueOf()
返回對象的字符串、數值、布爾值表示。通常與toString()方法的返回值相同。

拓展:聲明對象的幾種方式
```
<script>
//內置函數
var obj1=new Object();
obj1.name="zhuyu";
obj1.age=21;
obj1.uni=function(){
console.log(this.name+this.age);
}
console.log(obj1);
obj1.uni();
//字面量
var obj2={
name:"zhuyu2",
age:21,
uni2:function(){
console.log(this.name+this.age)
}
}
console.log(obj2);
obj2.uni2();
// 自定義函數
function Obj(name,age){
this.name=name;
this.age=age;
this.uni3=function(){
console.log(this.name+this.age)
}
}
var obj3=new Obj("zhuyu3",21);
console.log(obj3);
obj3.uni3();
// Es6類
class Obj2{
constructor(name,age){
this.name=name;
this.age=age;
}
uni4(){
console.log(this.name+this.age)
}
}
var obj4=new Obj2("zhuyu4",21);
console.log(obj4);
obj4.uni4();
//使用Object.create()
var person={
image:"true",
uni5:function(){
console.log(`名字是${this.name},年齡是${this.age}`);
}
}
var obj5=Object.create(person);
obj5.name="zhuyu5";
obj5.age=21;
obj5.image=false;
obj5.uni5();
console.log(obj5)
</script>
```
## 3、基本數據類型和引用數據類型的區別
**總結基本數據類型和引用數據類型區別**
**1、聲明變量時內存分配不同**
*原始類型:在棧中,因為占據空間是固定的,可以將他們存在較小的內存中-棧中,這樣便于迅速查詢變量的值

*引用類型:存在堆中,棧中存儲的變量,只是用來查找堆中的引用地址。


? ?這是因為:引用值的大小會改變,所以不能把它放在棧中,否則會降低變量查尋的速度。相反,放在變量的棧空間中的值是該對象存儲在堆中的地址。地址的大小是固定的,所以把它存儲在棧中對變量性能無任何負面影響
**2、不同的內存分配帶來不同的訪問機制**
? ??在javascript中是不允許直接訪問保存在堆內存中的對象的,所以在訪問一個對象時,首先得到的是這個對象在堆內存中的地址,然后再按照這個地址去獲得這個對象中的值,這就是傳說中的**按引用訪問**。
? ? 而原始類型的值則是可以直接訪問到的。
**3、復制變量時的不同**
?1)原始值:在將一個保存著原始值的變量復制給另一個變量時,會將原始值的副本賦值給新變量,**此后這兩個變量是完全獨立的,他們只是擁有相同的value而已。**
2)引用值:在將一個保存著對象內存地址的變量復制給另一個變量時,會把這個內存地址賦值給新變量,
也就是說這兩個變量都指向了堆內存中的同一個對象,他們中任何一個作出的改變都會反映在另一個身上。
(這里要理解的一點就是,復制對象時并不會在堆內存中新生成一個一模一樣的對象,只是多了一個保存指向這個對象指針的變量罷了)。**多了一個指針**
淺拷貝:

深拷貝:

**4、**參數傳遞的不同(**把實參復制給形參的過程**)****
首先我們應該明確一點:ECMAScript中所有函數的參數都是按值來傳遞的。
但是為什么涉及到原始類型與引用類型的值時仍然有區別呢?還不就是因為內存分配時的差別。
1)原始值:只是把變量里的值傳遞給參數,之后參數和這個變量互不影響。
2)引用值:對象變量它里面的值是這個對象在堆內存中的內存地址,這一點你要時刻銘記在心!
因此它傳遞的值也就是這個內存地址,這也就是為什么函數內部對這個參數的修改會體現在外部的原因了,因為它們都指向同一個對象。
## 4、檢測類型
* 法一:`typeof`
>最基本的判斷方式,該操作符返回一個表示數據類型的字符串,`number`、`string`、`boolean`、`object`、`function`、`undefined`、`symbol`
1. 'undefined'? ? ? ? ? ? ? --未定義的變量或值
2. 'boolean'? ? ? ? ? ? ? ? ?--布爾類型的變量或值
3. 'string'? ? ? ? ? ? ? ? ? ? ?--字符串類型的變量或值
4. 'number'? ? ? ? ? ? ? ? ??--數字類型的變量或值
5. 'object'? ? ? ? ? ? ? ? ? ? --對象類型的變量或值,或者null(這個是js歷史遺留問題,將null作為object類型處理)
6. 'function'? ? ? ? ? ? ? ? ?--函數類型的變量或值
? ? ? ?
```
console.log(typeof a);? ? //'undefined'
? ??console.log(typeof(true));? //'boolean'
? ? console.log(typeof '123');? //'string'
? ? console.log(typeof 123);? ?//'number'
? ??console.log(typeof NaN);? ?//'number'
? ? console.log(typeof null);? //'object'? ??
? ? var obj = new String();
? ? console.log(typeof(obj));? ? //'object'
? ? var? fn = function(){};
? ? console.log(typeof(fn));? //'function'
? ??console.log(typeof(class c{}));? //'function'
```
* 法二:`instanceof`
>**運算符用來測試一個對象在其原型鏈中是否存在一個構造函數的?`prototype`?屬性**
語法:`object instanceof constructor`
(1)基礎類型
```
let num = 1
num instanceof Number // false
num = new Number(1)
num instanceof Number // true
```
這兩個都是一樣的數值,為什么不一樣?
因為instanceof 檢測的是:檢測目標的`__proto__`與構造函數`prototype`,相同返回true,不同返回false,對于`string`、`boolean`是一樣的
注意:
```
new String(1) // String?{"1"}
String(1) // "1"
```
(2) 繼承關系的用法
```
// 判斷 foo 是否是 Foo 類的實例 , 并且是否是其父類型的實例
function Aoo(){}
function Foo(){}
Foo.prototype = new Aoo();//JavaScript 原型繼承
var foo = new Foo();
console.log(foo instanceof Foo)//true
console.log(foo instanceof Aoo)//true
```
(3) 復雜類型
```
let arr = []
arr instanceof Array // true
arr instanceof Object // true
Array.isArray(arr) // true
```
注意:
`(new Number(1)) instanceof Object // true`
(4) 其他類型
```
let reg = new RegExp(//)
reg instanceof RegExp // true
reg instanceof Object // true
let date = new Date()
date instanceof Date // true
date instanceof Object // true
```
但是`Fuction`不一樣
```
function A() {}
let a = new A()
a instanceof Function // false
a instanceof Object // true
A instanceof Function // true
```
-->分析`a`為什么不是?
>* a是new出來,所以是經過構造,因此已經是對象,不再是函數,所以false。
>* a是經過構造的對象,返回ture沒問題。
> * 如上所述,A是個函數,因此沒什么概念上的問題。但是要知道`A.__proto__`即`Function.prototype`是`? () { [native code] }`,這是與object以后處于原型鏈上層的存在,而且與object平級:
```
let obj = {}
obj.__proto__ // {constructor: ?, __defineGetter__: ?, __defineSetter__: ?, hasOwnProperty: ?, __lookupGetter__: ?,?…}
obj.__proto__.prototype // undefined
let A = function() {}
A.__proto__ // ? () { [native code] }
A.__proto__.prototype // undefined
```

- git-第一天
- Git-第二天
- git-第三天
- http-基礎
- HTTP構成和狀態碼
- 瀏覽器輸入URL,經歷的過程
- TCP/IP 詳解三次握手 四次揮手
- http-DNS系統
- http與https之間的區別
- HTTPS握手和HTTP握手
- HTTP小試牛刀
- Tcp初探
- TCP報文格式
- HTML5
- HTML基礎
- Mock
- css 選擇器
- css 動畫
- css 定位
- position/display/float/z-index第一課時
- 行內、塊、脫標 三種狀態下的元素如何實現、水平、垂直居中
- clientHeight/offsetHeight/scrollHeight
- js 數據類型
- 變量提升
- 堆棧關系