JS匯總---基礎(chǔ)&函數(shù)&閉包

基礎(chǔ)


Javascript是一種弱類型語言,它分別有什么優(yōu)點和缺點

弱類型語言:簡單好用,更靈活多變。但是會犧牲性能,比如一些隱含的類型轉(zhuǎn)換
強類型語言:類型轉(zhuǎn)換的時候非常嚴格,,強類型語言是直接操縱內(nèi)存,容易出內(nèi)存越界和泄漏的問題。在類型的轉(zhuǎn)換方面是很多約束,甚至強制轉(zhuǎn)換也要很謹慎,一不小心就出大問題。

Javascript里面的數(shù)據(jù)類型有哪些

5個簡單數(shù)據(jù)類型(基本數(shù)據(jù)類型)+ 1個復(fù)雜數(shù)據(jù)類型
undefiend, number string null boolean + object

有幾種方式可以判斷數(shù)據(jù)類型

typeof和intanceof
其實typeof和instanceof的目的都是檢測變量的類型,兩個的區(qū)別在于typeof一般是檢測的是基本數(shù)據(jù)類型,instanceof主要檢測的是引用類型!

typeof.png

基本類型和引用類型有什么區(qū)別

賦值的時候基本類型按值,引用類型按引用,就是基本類型會復(fù)制一份,引用類型就是一個新的指針
函數(shù)傳參的時候都是按值傳遞

{}=={}? []==[]? null==undefined?

{}=={}()
[]==[]()
null == undefined(對)

寫個方法判斷一個變量的類型

函數(shù)


函數(shù)聲明和函數(shù)表達式有什么區(qū)別

函數(shù)聲明會將那個函數(shù)提升到最前面,成為全局函數(shù)。函數(shù)聲明要指定函數(shù)名,而函數(shù)表達式不用,可以用作匿名函數(shù)。
創(chuàng)建函數(shù)的方式:函數(shù)聲明、函數(shù)表達式、還有一種不常見的方式就是Function構(gòu)造器
函數(shù)聲明:

function add(a,b) {
    a = +a;
    b = +b;
    if (isNaN(a) || isNaN(b)) {
        return;
    }
    return a + b;
}

函數(shù)表達式的幾種方式:

// 函數(shù)表達式
var add = function(a, b) {
    // do sth
}


// 匿名函數(shù)定義的一個立即執(zhí)行函數(shù)表達式
(function() {
    // do sth
})();


// 作為返回值的函數(shù)表達式
return function() {
    // do sth
};


// 命名式函數(shù)表達式
var add = function foo (a, b) {
    // do sth
}

函數(shù)聲明與函數(shù)表達式的主要區(qū)別就是:函數(shù)聲明會被前置
函數(shù)聲明前置:

// function add(a,b) 已經(jīng)聲明前置了,可以正常調(diào)用
var num = add(1, 2);
console.log(num);  // 3

function add(a,b) {
    a = +a;
    b = +b;
    if (isNaN(a) || isNaN(b)) {
        return;
    }
    return a + b;
}

函數(shù)表達式前置:

// var add 變量聲明提前,此時變量的值是undefined
var num = add(1, 2);
console.log(num);  // TypeError:undefined is not a function

var add = function(a, b) {
    a = +a;
    b = +b;
    if (isNaN(a) || isNaN(b)) {
        return;
    }
    return a + b;
}

Function構(gòu)造器:

var func = new Function('a', 'b', 'console.log(a+b);');
fun(1, 2); // 3

// 和上面的方式?jīng)]有區(qū)別
var func = Function('a', 'b', 'console.log(a+b);');
func(1, 2); // 3

區(qū)別:


360截圖20170307114742162.png

原型與原型鏈

每一個構(gòu)造函數(shù)都有一個prototype,指向一個對象,這個對象的所有屬性和方法,都會被構(gòu)造函數(shù)的實例繼承。
原型鏈作為實現(xiàn)繼承的主要方法。其基本思想是利用原型讓一個引用類型繼承另一個引用類型的屬性和方法。
在JavaScript中,用proto 屬性來表示一個對象的原型鏈。當(dāng)查找一個對象的屬性時,JavaScript 會向上遍歷原型鏈,直到找到給定名稱的屬性為止!

函數(shù)有哪幾種調(diào)用方式

直接調(diào)用
作為對象的方法調(diào)用
apply,call

作用域

JS沒有塊作用域,只有函數(shù)作用域
作用域鏈的作用是保證執(zhí)行環(huán)境里有權(quán)訪問的變量和函數(shù)是有序的,作用域鏈的變量只能向上訪問,變量訪問到window對象即被終止,作用域鏈向下訪問變量是不被允許的。

作用域鏈是什么

A://說的不是很清楚

閉包

閉包是什么

閉包是指有權(quán)訪問另一個函數(shù)作用域中的變量的函數(shù)

創(chuàng)建閉包的方式:
在一個函數(shù)內(nèi)部創(chuàng)建另一個函數(shù)

閉包的作用:
1.讓這些函數(shù)的值始終保存在內(nèi)存中

濫用閉包有什么副作用

由于閉包會攜帶包含它的函數(shù)的作用域鏈,因此會比其他函數(shù)占用更多的內(nèi)存。過度使用閉包可能會導(dǎo)致內(nèi)存占用過多,所以只在絕對必要時使用閉包。

閉包實現(xiàn)塊級作用域

(function() {

})();

閉包的作用/應(yīng)用

匿名自執(zhí)行函數(shù)、緩存、實現(xiàn)封裝(主要作用)、實現(xiàn)面向?qū)ο笾械膶ο?br> 1 匿名自執(zhí)行函數(shù)

我們知道所有的變量,如果不加上var關(guān)鍵字,則默認的會添加到全局對象的屬性上去,這樣的臨時變量加入全局對象有很多壞處,
比如:別的函數(shù)可能誤用這些變量;造成全局對象過于龐大,影響訪問速度(因為變量的取值是需要從原型鏈上遍歷的)。
除了每次使用變量都是用var關(guān)鍵字外,我們在實際情況下經(jīng)常遇到這樣一種情況,即有的函數(shù)只需要執(zhí)行一次,其內(nèi)部變量無需維護,
比如UI的初始化,那么我們可以使用閉包:

var datamodel = {    
    table : [],    
    tree : {}    
};    
     
(function(dm){    
    for(var i = 0; i < dm.table.rows; i++){    
       var row = dm.table.rows[i];    
       for(var j = 0; j < row.cells; i++){    
           drawCell(i, j);    
       }    
    }    
       
    //build dm.tree      
})(datamodel);   
```
我們創(chuàng)建了一個匿名的函數(shù),并立即執(zhí)行它,由于外部無法引用它內(nèi)部的變量,因此在執(zhí)行完后很快就會被釋放,關(guān)鍵是這種機制不會污染全局對象。

**2緩存**

再來看一個例子,設(shè)想我們有一個處理過程很耗時的函數(shù)對象,每次調(diào)用都會花費很長時間,那么我們就需要將計算出來的值存儲起來,當(dāng)調(diào)用這個函數(shù)的時候,首先在緩存中查找,如果找不到,則進行計算,然后更新緩存并返回值,如果找到了,直接返回查找到的值即可。閉包正是可以做到這一點,因為它不會釋放外部的引用,從而函數(shù)內(nèi)部的值可以得以保留。
```
var CachedSearchBox = (function(){    
    var cache = {},    
       count = [];    
    return {    
       attachSearchBox : function(dsid){    
           if(dsid in cache){//如果結(jié)果在緩存中    
              return cache[dsid];//直接返回緩存中的對象    
           }    
           var fsb = new uikit.webctrl.SearchBox(dsid);//新建    
           cache[dsid] = fsb;//更新緩存    
           if(count.length > 100){//保正緩存的大小<=100    
              delete cache[count.shift()];    
           }    
           return fsb;          
       },    
     
       clearSearchBox : function(dsid){    
           if(dsid in cache){    
              cache[dsid].clearSelection();      
           }    
       }    
    };    
})();    
     
CachedSearchBox.attachSearchBox("input1");    
```
這樣,當(dāng)我們第二次調(diào)用CachedSearchBox.attachSerachBox(“input1”)的時候,我們就可以從緩存中取道該對象,而不用再去創(chuàng)建一個新的searchbox對象。

**3 實現(xiàn)封裝**

可以先來看一個關(guān)于封裝的例子,在person之外的地方無法訪問其內(nèi)部的變量,而通過提供閉包的形式來訪問:
```
var person = function(){    
    //變量作用域為函數(shù)內(nèi)部,外部無法訪問    
    var name = "default";       
       
    return {    
       getName : function(){    
           return name;    
       },    
       setName : function(newName){    
           name = newName;    
       }    
    }    
}();    
     
print(person.name);//直接訪問,結(jié)果為undefined    
print(person.getName());    
person.setName("abruzzi");    
print(person.getName());    
   
得到結(jié)果如下:  
   
undefined  
default  
abruzzi  
```
4 **實現(xiàn)面向?qū)ο笾械膶ο?*
傳統(tǒng)的對象語言都提供類的模板機制,這樣不同的對象(類的實例)擁有獨立的成員及狀態(tài),互不干涉。雖然JavaScript中沒有類這樣的機制,但是通過使用閉包,我們可以模擬出這樣的機制。還是以上邊的例子來講:
```
function Person(){    
    var name = "default";       
       
    return {    
       getName : function(){    
           return name;    
       },    
       setName : function(newName){    
           name = newName;    
       }    
    }    
};    
     
     
var john = Person();    
print(john.getName());    
john.setName("john");    
print(john.getName());    
     
var jack = Person();    
print(jack.getName());    
jack.setName("jack");    
print(jack.getName());    
   
運行結(jié)果如下:  
   
default  
john  
default  
jack  
```
由此代碼可知,john和jack都可以稱為是Person這個類的實例,因為這兩個實例對name這個成員的訪問是獨立的,互不影響的。

####實現(xiàn)一個暴露內(nèi)部變量,而且外部可以訪問修改的函數(shù)
(get和set,閉包實現(xiàn)) 
```
var person = function(){    
    //變量作用域為函數(shù)內(nèi)部,外部無法訪問    
    var name = "default";       
       
    return {    
       getName : function(){    
           return name;    
       },    
       setName : function(newName){    
           name = newName;    
       }    
    }    
}();    
     
print(person.name);//直接訪問,結(jié)果為undefined    
print(person.getName());    
person.setName("abruzzi");    
print(person.getName());    
   
得到結(jié)果如下:  
   
undefined  
default  
abruzzi  
```


####從幾個li中取下標的閉包代碼
```
<ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
</ul>


var li=document.getElementsByTagName("li");

for(var i=0;i<li.length;i++) {
    (function(x) {
        li[x].onclick=function(){alert(x);}
    })(i);
}

```
####實現(xiàn)一個閉包的例子(實現(xiàn)了一個定時函數(shù)傳值的)
```
閉包:
for(var i = 0; i < 10; i++ ){
    (function(x){
        setTimeout(function(){
            console.log(x)
        },x*1000)
    })(i)
}
或者用全局變量實現(xiàn)

```
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容