問題
1.基礎(chǔ)類型有哪些?復(fù)雜類型有哪些?有什么特征?
在回答該問題之間先介紹一下JavaScript的內(nèi)存機制:
JavaScript中的內(nèi)存分為棧內(nèi)存和堆內(nèi)存。
- 棧內(nèi)存:先進(jìn)后出,寄存速度快,棧數(shù)據(jù)可共享,由系統(tǒng)自動分配,數(shù)據(jù)固定不夠靈活,空間大小有限制,超出則棧溢出。
- 堆內(nèi)存:順序隨意,寄存速度比棧內(nèi)存慢,由程序申請,操作簡單,儲存空間大(取決于系統(tǒng)有效虛擬內(nèi)存)
- 基本數(shù)據(jù)類型分為變量標(biāo)識和值,均保存在棧內(nèi)存,變量標(biāo)識指向其對應(yīng)的值。
- 引用數(shù)據(jù)類型相對較為復(fù)雜,分為值、值所在堆地址以及變量標(biāo)識,其中值保存在堆內(nèi)存中,變量標(biāo)識和值所在堆地址保存在棧內(nèi)存,變量標(biāo)識指向其對應(yīng)的值所在堆地址。
有了以上的概念再理解基礎(chǔ)類型和復(fù)雜類型就比較容易了:
- 基礎(chǔ)類型:指的是簡單的數(shù)據(jù)段。
在JavaScript中有五種基本數(shù)據(jù)類型:undefined、null、boolean、number和string。
基礎(chǔ)類型的變量標(biāo)識和值均保存在棧內(nèi)存中,所以可以直接操作保存在變量中的實際值。 - 復(fù)雜類型指的是由多個值構(gòu)成的對象:對象、函數(shù)、數(shù)組、正則等。
復(fù)雜類型的值是按引用訪問的。
引用類型的值保存在堆內(nèi)存中,變量標(biāo)識和值所在堆地址(這里的說法有很多,指針、對象的引用)保存在棧內(nèi)存。
操作對象時,實際上是操作是值所在的堆地址而不是實際值。
舉例:
var a = 1;
var b = a;
a = 2;
var c = {
"name":"hunger"
};
var d =c;
d["name"] = "hunger1";
console.log(a) //2
console.log(b) //1
console.log(c) //{name:"hunger1"}
console.log(d) //{name:"hunger1"}
用內(nèi)存機制來解析這個例子:
-
var a = 1;,步驟:- 聲明
a,查找棧內(nèi)存中是否存在a,不存在則創(chuàng)建,不管已存在還是新創(chuàng)建的a,都指向undefined - 為
a賦值,在棧內(nèi)存中查找1,無則棧內(nèi)存中創(chuàng)建1,然后讓a指向1;
- 聲明
-
var b = a;步驟:- 聲明
b(同聲明a的步驟) - 為
b賦值,在棧內(nèi)存中查找a,找不到則拋出錯誤,找到a則讓b指向a所指向的1。
- 聲明
-
a = 2;步驟:- 在棧內(nèi)存中查找
a,未找到則聲明一個全局對象a。 - 讓
a指向新的值2。
- 在棧內(nèi)存中查找
-
var c = {"name":"hunger"};步驟:- 聲明
c(同聲明a的步驟) - 為
c賦值,堆內(nèi)存中創(chuàng)建{"name":"hunger"},棧內(nèi)存中創(chuàng)建其堆地址ulr_c,讓c指向url_c
- 聲明
-
var d =c;步驟:- 聲明
d(同聲明a) - 為
d賦值,在棧內(nèi)存中查找c,找不到則拋出錯誤,找到c則讓d指向c所指向的url_c。
- 聲明
-
d["name"] = "hunger1";步驟:- 在棧內(nèi)存中查找
d,找不到則拋出錯誤,找到d則通過其指向的url_c找到堆內(nèi)存中的{"name":"hunger"} - 修改堆內(nèi)存中的
{"name":"hunger"}為{"name":"hunger1"}
- 在棧內(nèi)存中查找
-
輸出結(jié)果說明:
-
a指向2,輸出2。 -
b指向1,輸出1。 -
c指向url_c,url_c對應(yīng)在堆內(nèi)存中的值{"name":"hunger1"}輸出"name":"hunger1"。
-
d指向url_c,url_c對應(yīng)在堆內(nèi)存中的值{"name":"hunger1"}輸出"name":"hunger1"。
參考博客:
JavaScript的變量:變量值的數(shù)據(jù)類型
Js內(nèi)存機制詳解
2.如下代碼的輸出?為什么?
var obj1 = {a:1, b:2};
var obj2 = {a:1, b:2};
console.log(obj1 == obj2); ////false;由于obj1和obj2對象的指針不同,判斷后返回false。
console.log(obj1 = obj2); //{a:1,b:2} ,重新給obj1賦值,把obj2對象的指針賦值給ojb1。返回ojb2對象實際值。
console.log(obj1 == obj2);//true 此時,obj1和ojb2指針相同,判斷后返回true。
代碼
1.寫一個函數(shù)getIntv,獲取從當(dāng)前時間到指定日期的間隔時間。
function getIntv(time){
var dif = Date.parse(time) - Date.now();
var day = Math.floor(dif/(24*60*60*1000));
var hour = Math.floor(dif%(24*60*60*1000)/(60*60*1000));
var min = Math.floor(dif%(24*60*60*1000)%(60*60*1000)/(60*1000));
var sec = Math.floor(dif%(24*60*60*1000)%(60*60*1000)%(60*1000)/1000);
return "距除夕的日期還有"+day+"天"+hour+"小時"+min+"分鐘"+sec+"秒"
}
var str = getIntv("2017-01-28");
console.log(str);

運行結(jié)果
2.把數(shù)字日期改為中文日期
function getChsDate(val){
var zhArr = ["零","一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "十二", "十三", "十四", "十五", "十六", "十七", "十八", "十九", "二十", "二十一", "二十二", "二十三", "二十四", "二十五", "二十六", "二十七", "二十八", "二十九", "三十", "三十一"];
var dateStr = new Date(val);
var year = dateStr.getFullYear().toString();
var month = dateStr.getMonth()+1;//date對象的月份是從0開始算起,所以為了和中文索引匹配,這里要加上1。
var day = dateStr.getDate();
var resultYear = "";
for(var i=0; i < year.length; i++){
resultYear += zhArr[Number(year.substr(i,1))];
};
var resultMonth = zhArr[month];
var resultDay = zhArr[day];
return resultYear+"年"+resultMonth+"月"+resultDay+"日";
}
var str = getChsDate('2015-03-08');
console.log(str);

運行結(jié)果
3.寫一個函數(shù)獲取n天前的日期
function getLastNDays(n){
var dif= new Date(Date.now() -n*24*60*60*1000);
var year = dif.getFullYear();
var month = dif.getMonth()+1;
if(month < 10){
month = "0"+month;
}
var day = dif.getDate();
return year + "-"+month+"-"+day;
}
var lastWeek = getLastNDays(7); // ‘2016-01-08’
var lastMonth = getLastNDays(30); //'2015-12-15'

運行結(jié)果
4.完善如下代碼,用于獲取執(zhí)行時間如:
var Runtime = (function() {
var startTime,endTime;
var obj = {
start:function(){
startTime = Date.now()//當(dāng)前時間
},
end:function() {
endTime = Date.now() //結(jié)果時間
},
get:function(){
return endTime- startTime;//獲取執(zhí)行時間
}
};
return obj;
}());
Runtime.start();
for(var i=0; i<10000; i++){
console.log(1)
}
Runtime.end();
console.log(Runtime.get());

運行結(jié)果
5.樓梯有200級,每次走一級或是2級,從底到頂一共有多少種走法?用代碼(遞歸)實現(xiàn)。
思路:
1.當(dāng)走一級樓梯時,只有1種走法,
2.當(dāng)走二級樓梯時,有2種走法;
3.當(dāng)走三級樓梯時,要么從一級樓梯上跨2級,要么從二級樓梯上跨1級,所以,三級樓梯的走法是走一級樓梯的方法加上走二級樓梯的方法,即3種走法。
4.當(dāng)走四級樓梯時,同樣的思路,要么從二級樓梯上跨2級,要么從三級樓梯上跨一級,所以,四級樓梯的走法是走二級樓梯的方法加上走三級樓梯的方法,即5種走法。
5.以此類推,n級樓梯的走法,就是走(n-2)級樓梯的方法加上走(n-1)級樓梯的方法。
代碼:
function takeStairs(n){
if(n === 1){
return 1;
}else if(n === 2){
return 2;
} else {
return takeStairs(n-2)+takeStairs(n-1);
}
}
//由于200級數(shù)據(jù)太大,瀏覽器無響應(yīng),所以測試了一些小數(shù)據(jù)。

運行結(jié)果
6.寫一個json對象深拷貝方法,json對象可以多次嵌套,值可以是字符串、數(shù)字、布爾、json對象中的任意項。
function copyJson(json){
var newJson = {};
for (var key in json) {
if(typeof json[key] === "object"){
newJson[key] = copyJson(json[key]);
}else {
newJson[key] = json[key];
}
}
return newJson;
}
var json= {
"title": "Professional JavaScript",
"authors": [
"Nicholas C. Zakas"
],
"edition": 3,
"year": 2011
}
console.log(copyJson(json));

運行結(jié)果
本文版權(quán)歸本人和饑人谷所有,轉(zhuǎn)載請注明來源。