基礎(chǔ)
Javascript是一種弱類型語(yǔ)言,它分別有什么優(yōu)點(diǎn)和缺點(diǎn)
弱類型語(yǔ)言:簡(jiǎn)單好用,更靈活多變。但是會(huì)犧牲性能,比如一些隱含的類型轉(zhuǎn)換
強(qiáng)類型語(yǔ)言:類型轉(zhuǎn)換的時(shí)候非常嚴(yán)格,,強(qiáng)類型語(yǔ)言是直接操縱內(nèi)存,容易出內(nèi)存越界和泄漏的問題。在類型的轉(zhuǎn)換方面是很多約束,甚至強(qiáng)制轉(zhuǎn)換也要很謹(jǐn)慎,一不小心就出大問題。
Javascript里面的數(shù)據(jù)類型有哪些
5個(gè)簡(jiǎn)單數(shù)據(jù)類型(基本數(shù)據(jù)類型)+ 1個(gè)復(fù)雜數(shù)據(jù)類型
undefiend, number string null boolean + object
有幾種方式可以判斷數(shù)據(jù)類型
typeof和intanceof
其實(shí)typeof和instanceof的目的都是檢測(cè)變量的類型,兩個(gè)的區(qū)別在于typeof一般是檢測(cè)的是基本數(shù)據(jù)類型,instanceof主要檢測(cè)的是引用類型!

基本類型和引用類型有什么區(qū)別
賦值的時(shí)候基本類型按值,引用類型按引用,就是基本類型會(huì)復(fù)制一份,引用類型就是一個(gè)新的指針
函數(shù)傳參的時(shí)候都是按值傳遞
{}=={}? []==[]? null==undefined?
{}=={}()
[]==[]()
null == undefined(對(duì))
寫個(gè)方法判斷一個(gè)變量的類型
函數(shù)
函數(shù)聲明和函數(shù)表達(dá)式有什么區(qū)別
函數(shù)聲明會(huì)將那個(gè)函數(shù)提升到最前面,成為全局函數(shù)。函數(shù)聲明要指定函數(shù)名,而函數(shù)表達(dá)式不用,可以用作匿名函數(shù)。
創(chuàng)建函數(shù)的方式:函數(shù)聲明、函數(shù)表達(dá)式、還有一種不常見的方式就是Function構(gòu)造器。
函數(shù)聲明:
function add(a,b) {
a = +a;
b = +b;
if (isNaN(a) || isNaN(b)) {
return;
}
return a + b;
}
函數(shù)表達(dá)式的幾種方式:
// 函數(shù)表達(dá)式
var add = function(a, b) {
// do sth
}
// 匿名函數(shù)定義的一個(gè)立即執(zhí)行函數(shù)表達(dá)式
(function() {
// do sth
})();
// 作為返回值的函數(shù)表達(dá)式
return function() {
// do sth
};
// 命名式函數(shù)表達(dá)式
var add = function foo (a, b) {
// do sth
}
函數(shù)聲明與函數(shù)表達(dá)式的主要區(qū)別就是:函數(shù)聲明會(huì)被前置
函數(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ù)表達(dá)式前置:
// var add 變量聲明提前,此時(shí)變量的值是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ū)別:

原型與原型鏈
每一個(gè)構(gòu)造函數(shù)都有一個(gè)prototype,指向一個(gè)對(duì)象,這個(gè)對(duì)象的所有屬性和方法,都會(huì)被構(gòu)造函數(shù)的實(shí)例繼承。
原型鏈作為實(shí)現(xiàn)繼承的主要方法。其基本思想是利用原型讓一個(gè)引用類型繼承另一個(gè)引用類型的屬性和方法。
在JavaScript中,用proto 屬性來(lái)表示一個(gè)對(duì)象的原型鏈。當(dāng)查找一個(gè)對(duì)象的屬性時(shí),JavaScript 會(huì)向上遍歷原型鏈,直到找到給定名稱的屬性為止!
函數(shù)有哪幾種調(diào)用方式
直接調(diào)用
作為對(duì)象的方法調(diào)用
apply,call
作用域
JS沒有塊作用域,只有函數(shù)作用域
作用域鏈的作用是保證執(zhí)行環(huán)境里有權(quán)訪問的變量和函數(shù)是有序的,作用域鏈的變量只能向上訪問,變量訪問到window對(duì)象即被終止,作用域鏈向下訪問變量是不被允許的。
作用域鏈?zhǔn)鞘裁?/h4>
A://說(shuō)的不是很清楚
閉包
閉包是什么
閉包是指有權(quán)訪問另一個(gè)函數(shù)作用域中的變量的函數(shù)
創(chuàng)建閉包的方式:
在一個(gè)函數(shù)內(nèi)部創(chuàng)建另一個(gè)函數(shù)
閉包的作用:
1.讓這些函數(shù)的值始終保存在內(nèi)存中
濫用閉包有什么副作用
由于閉包會(huì)攜帶包含它的函數(shù)的作用域鏈,因此會(huì)比其他函數(shù)占用更多的內(nèi)存。過(guò)度使用閉包可能會(huì)導(dǎo)致內(nèi)存占用過(guò)多,所以只在絕對(duì)必要時(shí)使用閉包。
閉包實(shí)現(xiàn)塊級(jí)作用域
(function() {
})();
閉包的作用/應(yīng)用
匿名自執(zhí)行函數(shù)、緩存、實(shí)現(xiàn)封裝(主要作用)、實(shí)現(xiàn)面向?qū)ο笾械膶?duì)象
1 匿名自執(zhí)行函數(shù)
我們知道所有的變量,如果不加上var關(guān)鍵字,則默認(rèn)的會(huì)添加到全局對(duì)象的屬性上去,這樣的臨時(shí)變量加入全局對(duì)象有很多壞處,
比如:別的函數(shù)可能誤用這些變量;造成全局對(duì)象過(guò)于龐大,影響訪問速度(因?yàn)樽兞康娜≈凳切枰獜脑玩溕媳闅v的)。
除了每次使用變量都是用var關(guān)鍵字外,我們?cè)趯?shí)際情況下經(jīng)常遇到這樣一種情況,即有的函數(shù)只需要執(zhí)行一次,其內(nèi)部變量無(wú)需維護(hù),
比如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)建了一個(gè)匿名的函數(shù),并立即執(zhí)行它,由于外部無(wú)法引用它內(nèi)部的變量,因此在執(zhí)行完后很快就會(huì)被釋放,關(guān)鍵是這種機(jī)制不會(huì)污染全局對(duì)象。
**2緩存**
再來(lái)看一個(gè)例子,設(shè)想我們有一個(gè)處理過(guò)程很耗時(shí)的函數(shù)對(duì)象,每次調(diào)用都會(huì)花費(fèi)很長(zhǎng)時(shí)間,那么我們就需要將計(jì)算出來(lái)的值存儲(chǔ)起來(lái),當(dāng)調(diào)用這個(gè)函數(shù)的時(shí)候,首先在緩存中查找,如果找不到,則進(jìn)行計(jì)算,然后更新緩存并返回值,如果找到了,直接返回查找到的值即可。閉包正是可以做到這一點(diǎn),因?yàn)樗粫?huì)釋放外部的引用,從而函數(shù)內(nèi)部的值可以得以保留。
```
var CachedSearchBox = (function(){
var cache = {},
count = [];
return {
attachSearchBox : function(dsid){
if(dsid in cache){//如果結(jié)果在緩存中
return cache[dsid];//直接返回緩存中的對(duì)象
}
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”)的時(shí)候,我們就可以從緩存中取道該對(duì)象,而不用再去創(chuàng)建一個(gè)新的searchbox對(duì)象。
**3 實(shí)現(xiàn)封裝**
可以先來(lái)看一個(gè)關(guān)于封裝的例子,在person之外的地方無(wú)法訪問其內(nèi)部的變量,而通過(guò)提供閉包的形式來(lái)訪問:
```
var person = function(){
//變量作用域?yàn)楹瘮?shù)內(nèi)部,外部無(wú)法訪問
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 **實(shí)現(xiàn)面向?qū)ο笾械膶?duì)象**
傳統(tǒng)的對(duì)象語(yǔ)言都提供類的模板機(jī)制,這樣不同的對(duì)象(類的實(shí)例)擁有獨(dú)立的成員及狀態(tài),互不干涉。雖然JavaScript中沒有類這樣的機(jī)制,但是通過(guò)使用閉包,我們可以模擬出這樣的機(jī)制。還是以上邊的例子來(lái)講:
```
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());
運(yùn)行結(jié)果如下:
default
john
default
jack
```
由此代碼可知,john和jack都可以稱為是Person這個(gè)類的實(shí)例,因?yàn)檫@兩個(gè)實(shí)例對(duì)name這個(gè)成員的訪問是獨(dú)立的,互不影響的。
####實(shí)現(xiàn)一個(gè)暴露內(nèi)部變量,而且外部可以訪問修改的函數(shù)
(get和set,閉包實(shí)現(xiàn))
```
var person = function(){
//變量作用域?yàn)楹瘮?shù)內(nèi)部,外部無(wú)法訪問
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
```
####從幾個(gè)li中取下標(biāo)的閉包代碼
```
<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);
}
```
####實(shí)現(xiàn)一個(gè)閉包的例子(實(shí)現(xiàn)了一個(gè)定時(shí)函數(shù)傳值的)
```
閉包:
for(var i = 0; i < 10; i++ ){
(function(x){
setTimeout(function(){
console.log(x)
},x*1000)
})(i)
}
或者用全局變量實(shí)現(xiàn)
```