## **3.2.1 變量**
? 變量本質是一個空盒子,里面記錄了一個內存地址,使能找到內存中的對象,保存了指向具體的實在的東西的地址,變量存在棧中,對象存在堆中;
? 變量的意義:方便我們去操作對象。變量的幾種引用方式
- 指針(C語言中叫法)
- 引用(Java)
- 變量
> 例如:
> var b = document.body 含義:把body這個對象在內存中的地址放到b變量里面,變量b(b是內存地址的別名)本身也存在內存中,以后的操作是針對body這個地址
? 變量命名規范
- 由字母(a-zA-Z)數字(0-9)下劃線(_)以及美元符號($)
- 不能由數字開頭
- 命名盡量用英文并且具有一定的含義
- 如果有多個英文單詞,后面單詞的首字母大寫
- 不能使用關鍵字
- 首字母不要大寫,大寫是有特殊含義的
<br/>
## **3.2.2 JS數據類型**
**Javascript的數據類型有六種(ES6新增了第七種Symbol)**
- 數值(number):整數和小數(比如1和3.14)
- 字符串(string):字符組成的文本(比如”Hello World”)
- 布爾值(boolean):true(真)和false(假)兩個特定值
- undefined:表示 未定義 或不存在,即此處目前沒有任何值
- null:表示空缺,即此處應該有一個值,但目前為空
- 對象(object):各種值組成的集合
通常,我們將數值、字符串、布爾值稱為原始類型(primitive type)的值,即它們是最基本的數據類型,不能再細分了。
而將對象稱為合成類型(complex type)的值,因為一個對象往往是多個原始類型的值的合成,可以看作是一個存放各種值的容器。至于undefined和null,一般將它們看成兩個特殊值
> 內存中一共分為幾種對象:1.變量 2.DOM對象 3.常量 4.自定義對象
<br/>
## **3.2.3 如何判斷js中的數據類型**
typeof、instanceof、 constructor、 prototype方法比較
~~~js
如何判斷js中的類型呢,先舉幾個例子:
var a = "i am string.";
var b = 222;
var c= [1,2,3];
var d = new Date();
var e = function(){alert(111);};
var f = function(){this.name="22";};
~~~
- 最常見的判斷方法:typeof
~~~js
alert(typeof a) ------------> string
alert(typeof b) ------------> number
alert(typeof c) ------------> object
alert(typeof d) ------------> object
alert(typeof e) ------------> function
alert(typeof f) ------------> function
其中typeof返回的類型都是字符串形式,需注意,例如:
alert(typeof a == "string") -------------> true
alert(typeof a == String) ---------------> false
另外typeof可以判斷function的類型;在判斷除Object類型的對象時比較方便。
~~~
- 判斷已知對象類型的方法:instanceof
~~~js
alert(c instanceof Array) ---------------> true
alert(d instanceof Date) ---------------> true
alert(f instanceof Function) ------------> true
alert(f instanceof function) ------------> false
注意:instanceof后面一定要是對象類型,并且大小寫不能錯,該方法適合一些條件選擇或分支。
~~~
- 根據對象的constructor判斷:constructor
~~~js
alert(c.constructor === Array) ----------> true
alert(d.constructor === Date) -----------> true
alert(e.constructor === Function) -------> true
注意: constructor 在類繼承時會出錯
例子:
function A(){};
function B(){};
A.prototype = new B(); //A繼承自B
var aObj = new A();
alert(aobj.constructor === B) -----------> true;
alert(aobj.constructor === A) -----------> false;
而instanceof方法不會出現該問題,對象直接繼承和間接繼承的都會報true:
alert(aobj instanceof B) ----------------> true;
alert(aobj instanceof A) ----------------> true;
言歸正傳,解決construtor的問題通常是讓對象的constructor手動指向自己:
aobj.constructor = A; //將自己的類賦值給對象的constructor屬性
alert(aobj.constructor === A) -----------> true;
alert(aobj.constructor === B) -----------> false; //基類不會報true了;
~~~
- 通用但很繁瑣的方法: prototype
~~~js
alert(Object.prototype.toString.call(a) === ‘[object String]’) ------> true;
alert(Object.prototype.toString.call(b) === ‘[object Number]’) ------> true;
alert(Object.prototype.toString.call(c) === ‘[object Array]’) -------> true;
alert(Object.prototype.toString.call(d) === ‘[object Date]’) -------> true;
alert(Object.prototype.toString.call(e) === ‘[object Function]’) ---> true;
alert(Object.prototype.toString.call(f) === ‘[object Function]’) ---> true;
大小寫不能寫錯,比較麻煩,但勝在通用。
通常情況下用typeof判斷就可以了,遇到預知Object類型的情況可以選用instanceof或constructor方法
~~~
<br/>
## **3.2.4 數據類型轉換**
- **轉換函數**
- `toString()` 轉換為字符串,在JavaScript中所有數據類型都可以轉換為`string`類型
- `parseInt()`解析出一個`string`或者`number`類型的整數部分,如果沒有可以轉換的部分,則返回`NaN`(`not a number`)
~~~js
var n1 = "12";
var n2 = "23hello";
var n3 = "hello";
parseInt(n1); //12
parseInt(n2); //23
parseInt(n3); //NaN
~~~
- parseFloat()解析出一個`string`的浮點數部分,如果沒有可以轉換的部分,則返回`NaN`(not a number)
~~~js
var n1 = "1.2.3";
var n2 = "1.2hello"
var n3 = "hello"
parseFloat(n1); //1.2
parseFloat(n2); //1.2
parseFloat(n3); //NaN
~~~
- ##### **強制類型轉換**
- ##### `Boolean(value)`- 把給定的值轉換成`Boolean`型
- ##### `Number(value)`-把給定的值轉換成數字(可以是整數或浮點數)
- ##### `String(value)`- 把給定的值轉換成字符串
- ##### **隱式轉換**
- 數字+字符串:數字轉換為字符串 console.log(12+"12"); //1212
- 數字+布爾值:true轉換為1,false轉換為0 console.log(12+true); //13
- 字符串+布爾值:布爾值轉換為true或false
console.log("hello"+true); //hellotrue
- 布爾值+布爾值 console.log(true+true); //2
- **null和undefined**
undefined 表示一種未知狀態,聲明了但沒有初始化的變量,變量的值時一個未知狀態。訪問不存在的屬性或對象window.xxx)方法沒有明確返回值時,返回值是一個undefined.當對未聲明的變量應用typeof運算符時,顯示為undefined。
null表示尚未存在的對象,null是一個有特殊意義的值。可以為變量賦值為null,此時變量的值為“已知狀態”(不是undefined),即null。(用來初始化變量,清除變量內容,釋放內存)
> undefined==null //結果為true,但含義不同。
> undefined===null //false,兩者類型不一致,前者為“undefined”,后者為“object”
<br/>
#### 3.2.5 **運算符**
1.算術運算符(+, -, *, /, %, ++, --)
- 字符串和數字相加的情況:
- 左右都是數字:數字相加
- 左右有一個字符串:字符串拼接
- 左右邊有一個null:null看做0
- 左右邊有一個undefined:結果是NAN(not a number)
2.賦值運算符(=, -=, +=, *=, /=, %=)
3.比較運算符(\==, ===, !=, >, <, >=, <=)
> 先執行表達式計算再賦值
> \==和!=在比較之前首先讓雙方的值做隱士類型轉換,===不轉換
4.邏輯運算符(||, &&, !)
- || 在js中和PHP中是不一樣的 js中返回邏輯或的左邊或右邊的一個結果;PHP返回||或出來以后的結果即:true false
> 特殊性(注意):一定要記住(這個特性和其他編程語言不一樣):在js里返回不是布爾值
>
> || 短路運算,第一個條件為真,后面不執行
- &&把表達式最后一個值返回(注意這里)
條件運算符`(表達式1?表達式2:表達式3)`三元運算符
==表達式1?表達式2:表達式3==,表達式1為真,返回表達式2,否則返回表達式3
三元運算符可以多層次嵌套使用
- **在js中,有四種被認為是非**:
- `undefined`
- `null`
- `false`
- `0`
例子:`var age = prompt("溫馨提示:","請輸入您的年齡")||0`
當點擊取消的時候,如果出現`undefined` `null` `fasle` `0` 表示非的邏輯 那么`||`就會過濾,取右邊的值`0`
<br/>
## 3.2.6循環
>[info]console.log調試程序,開發中大量使用這個 而不用`alert`
- **js的斷點調試方法:**
1. 運行程序,按F12鍵或者右鍵鼠標找到“檢查”網頁
2. 在彈出的窗體選擇sources,點開源代碼,在想要設置斷點的地方的左邊代碼行單擊設置斷點
3. 然后要刷新一下頁面,頁面標題處于“圓圈”狀態,表明進入調試模式
4. 拉開最右邊的窗體,找到“watch”,可以添加想要檢測的變量。
- 條件結構
if
if...else
if...else if...else
當通過判斷返回某個值的時候,優先使用三元表達式
當通過判斷執行N段邏輯代碼的時候,只能用條件結構
- switch
switch case break default 條件 判斷 退出 默認
- a.只要匹配上一個case,那么它下面的所有的case都會執行包括default
- b.break的意思跳出當前結構
- for
for循環有三個要素
- a.循環變量
- b.判斷(循環體)
- c.改變循環變量
> continue 結束本次循環,繼續下一次循環,當前這次循環不做,直接做下面的
> break 跳出本層循環(只跳出一層)
- **while/do...while 沒有誰好誰壞 只有適應場景不同**
- 比如:先吃飯 在買單 do..while 用戶體驗高 有風險 掃雷游戲也是先體驗 在問是否退出 提高體驗
- 比如:先買單 在吃飯 while 用戶體驗不高
> 一般情況下,如果條件判斷是數字的比較`== <>`,for循環優先.
> 如果是非數值相關的比較循環,while優先
<br/>
## 3.2.7 Object對象
1.JS對象
? JS對象有內置對象,宿主對象(JS運行環境提供的對象 BOM DOM)和用戶自定義對象,自定義對象通過new關鍵字來創建,之后內存會為對象開辟一個新的內存空間,位于堆(heap)里面;
for...in 語句循環遍歷對象的屬性。
new關鍵字代表的是新開辟一塊內存空間,沒有被引用的內存空間,會在適當的時候被銷毀
以下兩句代碼含義等同
- var person = new Object();
- var person = {};
訪問對象的屬性除了用 對象引用`.屬性 key`以外,還可以使用對象引用`[屬性key]`
~~~js
<body>
<!--prototype 屬性允許您為對象構造器添加新屬性:-->
<script type="text/javascript">
function Person(){
name="hello";
age=11;
}
Person.prototype.nation="中國";
Person.prototype.eyecolor="black";
//構造器可以通過 構造器名.prototype 來拿到,或者添加原型屬性/方法
//由Person構造器實例化的對象通過.__proto__ 去拿到或者添加原型屬性。
var p1=new Person();
var p2=new Person();
//alert(Person.prototype == p1.__proto__);
p1.__proto__.eyecolor="黑色";
//alert(p2.__proto__.eyecolor);
/*你也可以直接通過對 象名.屬性名 去拿到構造器中已有的原型屬性
如果對象本身就有,則直接使用,如果沒有,對象會自動向上查找(構造器)
如果最后構造器中也沒有,才會返回undefined*/
//alert(p1.nation);
alert(p1.hhh+"沒找到此屬性");
//var arr=[1,2,3,5];
var arr=new Array();
arr[0]=1;
arr[1]=2;
arr[2]=3;
for (var s in arr) { //此時s就代表arr數組的下標
alert(arr[s]); //通過arr[下標]就可以得到數組的元素值
}
</script>
</body>
~~~
<br/>
2.new 原理詳細解析
------
- 無論什么時候,只要創建一個新函數,就會根據一組特定的規則為該函數創建一個`prototype`屬性,這個屬性指向函數的原型對象。
- 在默認情況下,所有原型對象都會自動獲得一個`constructor`(構造函數)屬性,這個屬性包含一個指向`prototype`屬性所在函數的指針(就是指向新創建的函數)。
- 通過這個構造函數(原型對象的構造函數),可以繼續為原型對象添加其他屬性和方法。
- >當調用構造函數創建一個新實例后,該實例的內部將包含一個指針(內部屬性),指向構造函數的原型對象。`ECMA-262`第5版管這個指針叫 `[[Prototype]]`。腳本中沒有標準的方式訪問`[[Prototype]]`,但`Firefox`、`Safari`和`Chrome`在每個對象上都支持一個屬性`__proto__`;而在其他實現中,這個屬性對腳本是完全不可見的。不過,要明確的真正重要的一點就是,這個連接存在于實例和構造函數的原型對象之間,而不是存在于實例和構造函數之間
3.new創建對象的步驟
------
- 創建一個新的對象
- 將構造函數的作用域賦給新對象
- 執行構造函數的代碼,為這個新對象添加屬性
- 返回新對象
**4.使用工廠方法創建對象**
~~~js
使用工廠方法創建對象,通過該方法可以大批量的創建對象
function createPerson(name , age ,gender){
//創建一個新的對象
var obj = new Object();
//向對象中添加屬性
obj.name = name;
obj.age = age;
obj.gender = gender;
obj.sayName = function(){
alert(this.name);
};
//將新的對象返回
return obj;
}
var obj2 = createPerson("豬八戒",28,"男");
var obj3 = createPerson("白骨精",16,"女");
var obj4 = createPerson("蜘蛛精",18,"女");
/*
* 使用工廠方法創建的對象,使用的構造函數都是Object
* 所以創建的對象都是Object這個類型,
* 就導致我們無法區分出多種不同類型的對象
*/
~~~
**5.構造器**
~~~js
<script type="text/javascript">
//構造器constructor
function person(name,age,sex){
this.name=name;
this.age=age;
this.sex=sex;
this.work=function () {
alert("人都要工作");
};
}
var tom=new person("tom",23,"男");
var bill=new person("bill",25,"男");
var jessie=new person("jessie",20,"女");
//tom instanceof person 表示判斷左邊的對象是否屬于右邊的類
alert(tom instanceof person); //true
</script>
~~~