那些必需要知道的Javascript

      JavaScript是前端必備,而這其中的精髓也太多太多,最近在溫習的時候發現有些東西比較容易忽略,這裏記錄一下,一方面是但願本身在平時應用的時候可以駕輕就熟,另外一方面也但願能給別人帶來一點點的收穫。前端

      1、JavaScript的==和===,即相等運算符和等同運算符。數組

      相等運算符,若是操做數有相同的類型,則判斷其等同性,若是兩個操做數的值相等,則返回true(相等),不然返回false(不相等);閉包

      若是類型不一樣,則按照這樣的狀況來判斷:ide

      null和undefined相等;數字與字符串字符比較,字符串轉化爲數字再比較;其中一個爲true轉化爲1再作比較;若是一個值是對象,另外一個是數字或者字符串,則將對象轉化爲原始值(經過toString()或者valueOf()方法),其餘返回false。函數

      等同運算符,若是操做數類型不同,直接返回false,類型相同,以下判斷:學習

      一、都是數字,若值相同,則二者等同可是NAN除外,由於NAN與自己也不等,不然不相同;spa

      二、都是字符串的狀況:值不等則不等同,不然等同;prototype

      三、都是布爾值,均爲true/false則等同不然不等同;3d

      四、若是兩個操做數引用同一對象(數組或函數)則等同,不然不等;code

      五、均爲null/undefined則等同。

       2、函數做用域

       做用域在全部語言中都有體現,只是在Javascript腳本里有其特殊性-->Javascript中的做用域爲函數體內有效,而無塊兒做用域。在Java或者C#中,咱們能夠寫出下面的循環:

public void method(string obj1,string obj2){
for(int i=0;i<obj1.length;i++){
//do  something
}
//此時的i爲未定義
for(int i=0;i<obj2.length;i++){
//do another thing
}
}
View Code

而在Javascript中不一樣:

function func(){
for(var i = 0; i < array.length; i++){
//do something here.
}
//此時i仍然有值,及I == array.length
print(i);//i == array.length;
}
View Code

      Javascript的函數是在局部做用域內運行的,在局部做用域內運行的函數體能夠訪問其外層的(多是全局做用域)的變量和函數。JavaScript的做用域爲詞法做用域,所謂詞法做用域是說,其做用域爲在定義時(詞法分析時)就肯定下來的,而並不是在執行時肯定,以下例:

var str = "global";
function scopeTest(){
print(str);
var str = "local";
print(str);
}
scopeTest();
View Code

      您以爲運行結果是什麼呢?global local或者local  local 再或者其餘?而正確的結果倒是 undefined   local,沒錯,undefined  local!

      由於在函數scopeTest的定義中,預先訪問了未聲明的變量str,而後纔對str變量進行初始化,因此第一個print(str)會返回undifined錯誤。那爲何函數這個時候不去訪問外部的str變量呢?這是由於,在詞法分析結束後,構造做用域鏈的時候,會將函數內定義的var變量放入該鏈,所以str在整個函數scopeTest內都是可見的(從函數體的第一行到最後一行),因爲str變量自己是未定義的,程序順序執行,到第一行就會返回未定義,第二行爲str賦值,因此第三行的print(str)將返回」local」。

      3、數組操做

      經常使用的對數組的操做:

      contact() 鏈接兩個或更過的數組,並返回結果

      join() 把數組全部元素放入一個字符串,元素經過指定的分隔符進行分隔

      pop() 刪除並返回最後一個元素與push()對應,向數組末尾添加一個或更多元素,並返回新長度;相似於壓棧和彈棧

      reverse() 顛倒元素的順序

      shift() 刪除並返回第一個元素

      slice() 從已有數組返回制定數組

      sort() 對數組元素排序,默認按字母排序,也可按數字大小排:array.sort(function(a,b){return a-b});

      splice()刪除元素,並添加新元素

      unshift()向數組開頭添加一個或更多元素,並返回新的長度

      valueOf() 返回數組對象的原始值

      4、JavaScript閉包特性

      咱們來看一個例子,若是不瞭解JavaScript的特性,很難找到緣由:

var outter = [];
function clouseTest () {
var array = ["one", "two", "three", "four"];
for(var i = 0; i < array.length;i++){
var x = {};
x.no = i;
x.text = array[i];
x.invoke = function(){
print(i);
}
outter.push(x);
}
}
//調用這個函數
clouseTest();
print(outter[0].invoke());
print(outter[1].invoke());
print(outter[2].invoke());
print(outter[3].invoke());
View Code

      運行的結果如何呢?0 1 2 3?這是不少人指望的答案,但是事實真的是這樣嗎?立刻運行一下吧,是否是驚呆了?結果竟然是4 4 4 4 !

      其實,在每次迭代的時候,這樣的語句x.invoke = function(){print(i);}並無被執行,只是構建了一個函數體爲」print(i);」的函數對象,如此而已。而當i=4時,迭代中止,外部函數返回,當再去調用outter[0].invoke()時,i的值依舊爲4,所以outter數組中的每個元素的invoke都返回i的值:4。如何解決呢,咱們能夠聲明一個匿名函數,而後立刻執行它。

function clouseTest2(){
var array = ["one", "two", "three", "four"];
for(var i = 0; i < array.length;i++){
var x = {};
x.no = i;
x.text = array[i];
x.invoke = function(no){
return function(){
print(no);
}
}(i);
outter.push(x);
}
}
View Code

      這個例子中,咱們爲x.invoke賦值的時候,先運行一個能夠返回一個函數的函數,而後當即執行之,這樣,x.invoke的每一次迭代器時至關與執行這樣的語句:

//x == 0
x.invoke = function(){print(0);}
//x == 1
x.invoke = function(){print(1);}
//x == 2
x.invoke = function(){print(2);}
//x == 3
x.invoke = function(){print(3);}
View Code

      這樣就能夠獲得正確的結果了。

      能夠根據Object.prototype.toString.Call(source)來判斷給定對象的類型。另外還有兩個地方須要注意:

      一、若是變量做用域爲函數內部則,則外部沒法訪問,如:

var person=function(){
var name="default";
return {
getName:function(){return name;},
setName:function(no){name=no}
}
}();
print(person.name)//undefined
View Code

      二、引用

      引用也是一個比較有意思的主題,JavaScript中的引用始終指向最終的對象,而並不是引用自己,咱們來看一個例子:    

var obj = {};//空對象
var ref = obj;//引用
obj.name = "objectA";
print(ref.name);//ref跟着添加了name屬性
obj = ["one", "two", "three"];//obj指向了另外一個對象(數組對象)
print(ref.name);//ref還指向原來的對象
print(obj.length);//3
print(ref.length);//undefined
View Code

      運行結果:

      objectA
      objectA
       3
      undefined

      obj只是對一個匿名對象的引用,因此,ref並不是指向它,當obj指向另外一個數組對象時能夠看到,引用ref並未改變,而始終指向那個後來添加了name屬性的"空"對象」{}」。理解這個以後,下面這個例子就不難了:

var obj = {};//新建一個對象,並被obj引用
var ref1 = obj;//ref1引用obj,事實上是引用obj引用的空對象
var ref2 = obj;
obj.func = "function";
print(ref1.func);
print(ref2.func);
View Code

      聲明一個對象,而後用兩個引用來引用這個對象,而後修改原始的對象,注意這兩步的順序,運行之:

     function
     function

     根據運行結果咱們能夠看出,在定義了引用以後,修改原始的那個對象會影響到其引用上,這一點也應該注意。

     以上是最近發現的一些易錯的地方,也但願您能將您遇到的易錯問題分享出來,一塊兒學習,共同進步!

相關文章
相關標籤/搜索