js筆記—— 基礎部分一

鬆鬆個人網絡日誌地址

前言:js由三部分組成,1. 核心(ECMAScript),語法標準    2.文檔對象模型(DOM)    3.瀏覽器對象模型(BOM)

JavaScript 的核心語言特性在ECMA-262中是以名爲ECMAScript的僞語言的形式來定義的。ECMAScript中包含了所有基本的語法,操作符,數據類型以及完成基本的計算任務所必需的對象,但沒有對取得輸入和產生輸出的機製作出規定。

1.在web中引入js

<script></script>    使html與js混合

defer  :  延遲到頁面全部解析完後再加載js

type : mime類型, 默認"text/javascript"。可省略

引入外部js:

<script src=""></script> 可引入不用域的js,引入外部js時同時在標籤內嵌入js代碼會被忽略。

 注意:不要在js中出現 </script> ,會造成瀏覽器錯誤解析(以爲js已經結束)。

 小tips:瀏覽器按照<script>標籤先後順序解析,如果將js代碼放head裏,瀏覽器會先解析js,然後呈現body中的頁面元素(頁面延遲,呈現空白)

2.數據類型

ECMAScript 中規定的5種基本數據類型:  Undefined,Null,Boolean,Number,String

      1種複雜數據類型:  Object   由一組無序的鍵值對組成

typeof操作符: 用於返回檢測的變臉類型   :  undefined,object,boolean,number,string,function

typeof(null); //返回"object"  空對象指針(對空對象的引用)

Undefined類型

只有一個值  undefined,變量聲明後未初始化,值就是undefined。(未聲明和聲明後未定義值都是undefined)
var name;
alert(name);//"undefined"
alert(age);//"undefined"

Null類型

同樣只有一個值  null。
var name = null;
alert(typeof  name);//"object" 對空指針的引用
小tips:在定義一個變量用來保存對象時,初始化時最後給null,這樣就只需要檢查null值就可以判斷變量是否保存了對象的引用.

  如:

var person = null;
if(person!=null){

}
alert(null == undefined); //true,  undefined值是派生自null值的

Boolean類型

任何其他類型都有與Boolean等價的值
Boolean(""); //false,   非空字符串返回true
Boolean(0);//0和NaN 返回 false ,   非零(包括無窮大)返回true
Boolean(null);//返回false
Boolean(undefined);//false

使用if語句進行流程控制時,會自動調換用Boolean()函數進行轉換

Number類型

var num1 = 55;  //十進制
var num2 = 070; //八進制  0開頭   56
var num3 = 0x1f; // 十六進制  0x開頭   31
  1. 浮點數值
由於保存浮點數值需要的存儲空間是整數值的兩倍,所以ECMAScript會儘可能將浮點數轉成整數。
var floatNum1 = 10.0; //保存的是整數10
注意:0.1+0.2 !=0.3 浮點數精度問題(永遠不要測試某個特定的浮點數值)
2. 數值範圍
Number.MAX_VALUE,Number.MIN_VALUE,Number.NEGATIVE_INFINITY,Number.POSTIVE_INFINITY
Infinity正無窮, -Infinity負無窮。
isFinite()函數來判斷是否在這個範圍內,超出範圍的數值會被自動轉成相應的無窮大值
3. NaN(Not a Number)非數值
任何數值除以0返回NaN,不會拋錯(不會影響後面代碼的執行)
注意:任何涉及NaN的操作都會返回NaN。NaN與任何值都不相等(包括NaN)
alert(NaN == NaN); //false
isNaN();//判斷是否 "不是數值"
alert(isNaN(NaN));  // true
alert(isNaN(10));  //false
alert(isNaN("10"));  //false,可轉換成數值 
alert(isNaN("blue"));  //true,不可轉成數值 
alert(isNaN(true));    //false 可轉成數值 
4. 數值轉換函數 Number() ,parseInt()和parseFloat()
Number(null); // 0
Number(undefined); //NaN
Number("hehe"); //NaN
Number(""); //0

parseInt("0xAF",16); //175
parseInt("AF"); //NaN 需指定進制
parseInt("10",2); // 2 (二進制)

String 類型

由零或多個 16位 Unicode字符組成的字符序列
注意:字符串一旦創建,值就不能改變。如果改變,是先銷燬原來的字符串,然後用新字符串來填充該變量
字符串轉換:
toString();幾乎每個值都有該方法
toString(2); //可指定數值的轉換進制
null和undefined沒有 toString()函數
可以使用String()函數來轉換:String(null); // "null"
String(undefined); //"undefined"

Object類型 (所有對象的基礎)

Obejct屬性和方法
Constructor:構造函數(用於創建當前對象的函數)
hasOwnProperty(propertyName):檢索當前對象實例中的屬性(不是實例原型)是否存在,參數必須是字符串
isPrototypeOf(object):傳入的對象是否是另一個對象的原型
propertyIsEnumerable(propertyName):屬性是否能用for-in 遍歷
toLocalString():返回對象的字符串表示
toString():
valueOf():返回對象的字符串,數值或布爾值表示。通常與toString()返回相同

3.操作符

1.位操作符

32二進制表示整數,第32位爲符號位
~ 按位非(NOT)
& 按位與(AND)
| 按位或(OR)
^ 按位異或(XOR)
<< 左移,不影響符號位
>> 有符號右移,保留符號位,不影響正負
<<< 無符號右移,連着符號位一起右移

2.關係操作符

4.語句

1.for-in 精準的迭代語句,可以用來枚舉對象的屬性

for(var propName  in window){
      document.write(propName);
}
輸出BOM中 window對象的所有屬性
迭代前最好先檢測對象是否爲null或undefined。(ECMAScript5中不執行循環體,以前會報錯)

2.label語句,給代碼添加標籤

3.break和continue語句(break跳出循環,直接執行循環後的代碼。continue跳出當前循環,接着進入下一次循環)

var num =0;
outer:
      for(var i=0;i<10;i++){
           for(var j=0;j<10;j++){
                if(i == 5 && j==5){
                      continue   outer;
                }
                num++;
           }
      }
alert(num);    //95

4.  with語句(不建議使用,可讀性差)

5. switch語句

var num = 15;
switch (true){  //輸出  Between 10 and 20,如果是false就輸出  Less than 0
	case num<0:
	alert("Less than 0");
	break;
	case num>=0&&num<=1:
	alert("Between 0 and 1");
	break;
	case num>10&&num<=20:
	alert("Between 10 and 20");
	break;
	default:
		alert("More than 20");
}

6.函數

function關鍵字來定義函數,
注意:函數無所謂傳進來多少個參數。因爲在內部是用一個數組來表示的,在函數體內可以通過arguments來訪問這個數組。
arguments對象只是與數組類似(並不是array的實例)
function doAdd(num1,num2){
      arguments[1] = 10;    //會同步影響 num2的值,這種影響是單向的,反過來修改num2並不會影響arguments中的值
      alert(arguments[0]+num2);
}
注意:arguments對象長度由傳入的參數個數決定,不由定義函數時聲明的參數個數決定,沒有傳值的參數自動賦值undefined

5.變量,作用域,內存

5.1  基本類型和引用類型

基本類型值指的是簡單的數據段,而引用類型值指那些可能由多個值構成的對象。
基本類型是按值訪問,所以可以操作保存在變量中的實際的值。
引用類型的值是保存在內存中的對象,js不允許直接 訪問內存中的位置(不能直接操作對象的內存空間),實際操作的是對象的引用。
var person = new Object();
person.name = "張三";  //給引用類型變量動態添加屬性並賦值
alert(person.name);//  張三
//無法給基本類型變量添加屬性,不報錯但是無效。

變量複製:  基本類型

var num1 = 5;
var num2 = num1;// num1和num2是兩個獨立的值,在進行任何操作時不會相互影響。
引用類型:

var obj1  = new Object();
var obj2 = obj1;
obj1.name = "張三";
alert(obj2.name);  // 張三  
//obj1和obj2指向的是堆內存中的同一個對象

參數傳遞:

ECMAScript中所有函數的參數都是按值傳遞的。在傳遞基本類型值是,被傳遞的值會賦給一個局部變量(命名參數,arguments對象中的一個元素)

注意:傳遞引用類型時,會把這個值在內存中的地址賦值給一個局部變量(對堆內存中對象的引用),所以指向的還是同一個內存空間,因此對參數的修改會影響到函數外。

function setName(obj){
     obj.name = "張三";//obj引用指向堆中的person對象,person.name = "張三"
     obj = new Object();//給obj(參數,局部變量)  指向新的對象(該對象在setName函數中創建,是局部的,函數結束,對象銷燬)
     obj.name = "李四";//給obj引用的局部變量動態添加name屬性賦值爲"李四"
}
var person = new Object();
setName(person);
alert(person.name); //張三
類型檢測:

通常用typeof來檢測基本類型

instanceof來檢測引用類型,根據它的原型鏈來識別。

所有引用類型都是Object的實例,用instanceof檢測所有基本數據類型,都會返回false。基本類型 不是對象。

5.2 執行環境及作用域

說明:執行環境定義了變量或函數有權訪問的其他數據,決定了他們各自的行爲。每個執行環境都有一個與之關聯的變量對象(variable object),環境中定義的所有變量和函數都保存在這個對象中。雖然我們編寫的代碼無法訪問這個對象,但解析器在處理數據是會在後臺使用它。

全局執行環境是最外圍的一個執行環境。在web瀏覽器中,全局執行環境就是window對象,因此所有全局變量和函數都是作爲window對象的屬性和方法

創建的。某個執行環境中的所有代碼執行完後,保存在其中的變量和函數定義也隨之銷燬。

每個函數都有自己的執行環境。當執行流進入一個函數時,函數環境會被推入環境棧。執行完後彈出棧,控制權交給之前的執行環境

作用域鏈(scope chain)。保證對執行環境有權訪問的所有變量和函數的有序訪問
 
var color = "blue";
function changeColor(){
      var anotherColor = "red";
      function swapColors(){
               var  temColor = color;
               color = anotherColor;
               anotherColor = temColor;
      }
}
上面代碼作用域鏈,如圖:三個作用域,內部環境可以通過作用域鏈訪問所有的外部環境
延長作用域鏈:

1.try-catch 中的catch塊

2.with語句

function buildUrl(){
	var qs = "?debug=true";
	with(location){
		var url = href + qs;  //location.href,url添加到最近的環境(buildUrl函數中)
	}
	return url; 
}
with語句接收的是location對象,因此其變量對象中就包含了location對象的所有屬性和方法,而這個變量對象被添加到了作用域鏈的前端,所以在函數內部可以訪問。

沒有塊級作用域:
js沒有塊級作用域,不像java等語言,if(){},for(){}語句中定義的都是局部變量
for(var i=0;i<10;i++){
     doSomething(i);
}
alert(i);   // 10   
js中會將if,for中聲明的變量添加到當前的執行環境中
變量聲明:
使用var聲明的變量會自動被添加到最接近的環境中。在函數內部,最接近的就是當前函數的局部環境;在with語句中,最接近的環境是函數環境。如果初始化變量時沒有var聲明,則自動添加到全局環境。
function(num1,num2){
        sum = num1+num2; //sum未聲明,添加到全局環境
        return sum;
}
var result = add(10,20); //30
alert(sum);    //30,可訪問到
查詢標識符:同名變量,從最近環境開始搜索,優先取最近環境中的值然後停止搜索。

5.3 垃圾收集

說明:JavaScript具有自動垃圾收集機制,執行環境會負責管理代碼執行過程中使用的內存

局部變量只在函數執行的過程中存在。在這個過程中,會爲局部變量在棧(或堆)內存上分配相應的空間,以便存儲它們的值。在函數執行結束,局部變量就沒有存在的必要,因此可以釋放它們的內存。

標記清除
JavaScript中最常用的垃圾收集方式是標記清除(mark-and-sweep)。當變量進入環境時(如:在函數中聲明一個變量),就將這個變量標記爲"進入環境",當變量離開環境時,則將其標記爲"離開環境"。

垃圾收集器在運行的時候會給存儲在內存中的所有變量加上標記,然後會去除環境中的變量以及被環境中的變量引用的變量的標記。

在此之後再被加上標記的變量將被視爲準備刪除的變量(環境中變量已經無法訪問這些變量了)。最後,垃圾收集器完成內存清除工作,銷燬帶標記的值並回收內存空間。

引用計數

說明:引用技術會跟蹤每個值被引用的次數。當聲明瞭一個變量並將一個引用類型值賦給該變量,則這個值的引用次數就是1。如果該值又被賦給另外一個變量,則該值的引用次數加1。相反,如果對這個值引用的變量取得了另外一個值,則這個值的引用次數減一。當這個值的引用次數變成0的時候,就說明沒法再訪問這個值了,就可以將其佔用的內存回收。當垃圾收集器下次再運行的時候就會釋放這些空間。
問題:對象之間循環引用會造成內存無法回收
function problem(){
	var objectA = new Object();
	var objectB = new Object();
	objectA.someOtherObject = objectB;
	objectB.anotherObject = objectA;
}
A,B對象通過各自的屬性相互引用。它們之間的引用次數永遠不會是0。如果這個函數被重複多次調用,就會導致大量內存無法回收。
問題:IE中有一部分並不是原生JS對象,BOM和DOM中的對象就是使用C++以COM(Component  Object  Model,組件對象模型)對象的形式實現的,而COM對象的垃圾收集機制採用的就是引用計數策略。所以,即使IE的JS引擎是使用標記清除策略,但JS訪問的COM對象依然是基於引用計數策略的。這就照成只要在IE中涉及COM對象就會存在內存引用的問題。
var element = document.getElementById("some_element");
var myObject = new Object();
myObject.element = element;
element.somObject = myObject;//DOM元素和JS對象相互引用,循環引用照成即使DOM從頁面中移除,它也不會被回收。

可以通過賦值爲null來手動斷開這兩個元素間的引用。如:
myObject.element =null;
element.somObject = null;
IE9中把BOM和DOM對象都轉成了JS對象,也可以避免兩種垃圾回收算法並存的問題(消除常見的內存泄漏現象)。

性能問題

說明:垃圾收集器是週期性運行的,原IE7策略問題:根據內存分配量運行,達到256個變量,4096個對象(或數組)或者64KB其中任一標準,垃圾收集器就會運行,這就導致如果一個腳本中包含這麼多變量,那麼這個腳本在器生命週期中很可能會一直保有這麼多變量。這樣一來,垃圾收集器就會頻繁運行,導致性能急劇下降。

解決方法:如果回收的內存分配量低於15%,則臨界值加倍。如果到了回收85%的內存分配量,就將臨界值重置回默認值。這樣循環往復,看似簡單,實則極大提升了IE在運行包含大量JS的頁面時的性能。

5.4 內存管理

說明:出於安全考慮,瀏覽器的可用內存數量比較少(防止運行JS的網頁耗盡全部系統內存而導致系統崩潰)。內存限制不僅影響給變量分配內存,同時還會影響調用棧以及在一個線程中能夠同時執行的語句數量。

tips:一旦數據不再有用,最好通過將其值設置爲null來釋放其引用(解除引用dereferencing)。該做法適用大多數全局變量和全局對象屬性。局部變量會在它們離開執行環境時自動被解除引用

function createPerson(name){
	var localPerson  = new Object(); //localPerson局部變量,不用手工解除
	localPerson.name = name;
	return localPerson;
}
var globalPerson = createPerson();
//手動解除globalPerson的引用
globalPerson = null;

解除globalPerson的引用,讓值脫離執行環境,以便垃圾收集器下次運行時將其回收

小結:

  • 基本類型值在內存中佔據固定大小的空間,被保存在棧內存中
  • 從一個變量向另一個變量複製基本類型的值,會創建這個值的一個副本
  • 引用類型的值是對象,保存在堆內存中
  • 包含引用類型值的變量實際上包含的並不是對象本身,而是一個指向該對象的指針
  • 從一個變量向另一個變量複製引用類型的值,複製的其實是指針,因此兩個變量最終都指向同一個對象
  • 確定一個值是哪種基本類型使用typeof(),確定值是哪種引用類型使用instanceof()

所有變量都存在於一個執行環境(作用域)中,這個執行環境決定了變量的生命週期,以及哪一部分代碼可以訪問其中的變量。

  • 執行環境有全局執行環境和函數執行環境之分;
  • 每次進入一個新執行環境,都會創建一個用於搜索變量和函數的作用域鏈;
  • 函數的局部環境不僅有權訪問函數作用域中的變量,而且有權訪問其父環境,乃至全句環境中的變量;
  • 全局環境只能訪問在全局環境中定義的變量和函數,而不能直接訪問局部環境中的任何數據;
  • 變量的執行環境有助於確定應該何時釋放內存
JavaScript是自動進行垃圾回收的,開發人員不必關心內存分配和回收問題。
  • 離開作用域的值將被自動標記爲可以回收,因此將在垃圾收集期間被刪除。
  • "標記清除"是目前主流的垃圾收集算法,思想就是給當前不使用的值加上標記,然後再回收其內存
  • "引用計數"的思想是跟蹤記錄所有值被引用的次數,JS引擎目前都不使用這種算法
  • 在代碼中循環引用時,"引用計數"算法會出現問題(內存泄漏)
  • 解除變量引用不僅有助於消除循環引用現象,而且對垃圾收集也有好處。爲了確保有效地回收內存,應該及時解除不再使用的全局對象,全局對象屬性及循環引用變量的引用。
鬆鬆個人網絡日誌
發佈了49 篇原創文章 · 獲贊 12 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章