1.基礎(chǔ)類型有哪些?復(fù)雜類型有哪些?有什么特征?
- 基礎(chǔ)數(shù)據(jù)類型:指的是簡單的數(shù)據(jù)段
- 在JavaScript中有五種基本數(shù)據(jù)類型:undefined、null、boolean、number和string。
- 解析:基礎(chǔ)類型是保存在棧內(nèi)存中的簡單數(shù)據(jù)段。通過變量復(fù)制基礎(chǔ)類型值的時候,會建立新的內(nèi)存并在新內(nèi)存中保存相同的值。修改新的變量值不會影響被復(fù)制的變量值。
var a ="hello"
var b = a
a = "hi"
console.log(b)//"hello"
console.log(a)//"hi"
- 復(fù)雜類型:指的是由多個值構(gòu)成的對象,包括:對象、函數(shù)、Date對象、數(shù)組、正則等
- 解析:復(fù)雜類型也屬于引用類型。對象作為引用類型,實際上是保存在堆內(nèi)存中。而變量中保存的是指向?qū)ο笏趦?nèi)存位置的指針。通過變量復(fù)制對象的時候,新變量的指針指在相同的內(nèi)存位置。所以通過新變量修改數(shù)值的時候,被復(fù)制的變量所指向的值也會相應(yīng)改變。
var obj1={
name:"ff",
age:18
}
var obj2=obj1
obj2.name = "vv"
console.log(obj2)//Object {name: "vv", age: 18}
console.log(obj1)//Object {name: "vv", age: 18}
基礎(chǔ)類型和復(fù)雜類型的特征
(1)基礎(chǔ)類型的特征是存儲在棧內(nèi)存中,按值訪問,可以操作存儲在變量中的實際的值
(2)復(fù)雜類型的特征是存儲在堆內(nèi)存中,按指針訪問,操作復(fù)雜類型的對象時實際上是操作對象的引用(指針),而非實際的對象介紹一下JavaScript的內(nèi)存機制
JavaScript中的內(nèi)存分為棧內(nèi)存和堆內(nèi)存。
棧內(nèi)存:先進后出,寄存速度快,棧數(shù)據(jù)可共享,由系統(tǒng)自動分配,數(shù)據(jù)固定不夠靈活,空間大小有限制,超出則棧溢出。
堆內(nèi)存:順序隨意,寄存速度比棧內(nèi)存慢,由程序申請,操作簡單,儲存空間大(取決于系統(tǒng)有效虛擬內(nèi)存)
基本數(shù)據(jù)類型分為變量標識和值,均保存在棧內(nèi)存,變量標識指向其對應(yīng)的值。
引用數(shù)據(jù)類型相對較為復(fù)雜,分為值、值所在堆地址以及變量標識,其中值保存在堆內(nèi)存中,變量標識和值所在堆地址保存在棧內(nèi)存,變量標識指向其對應(yīng)的值所在堆地址。
參考(必看)Js內(nèi)存機制詳解
2.如下代碼的輸出? 為什么?
var obj1 = {a:1, b:2};
var obj2 = {a:1, b:2};
console.log(obj1 == obj2);//false 因為是兩個不同的對象,跟它們的值相同沒什么關(guān)系。
console.log(obj1 = obj2);//var obj1 = {a:1,b:2} //將obj2賦值給obj1。這時obj1指向obj2內(nèi)存中對象的值。
console.log(obj1 == obj2);//true 上面那個操作讓兩者指向同一引用地址了,所以是true
3.寫一個函數(shù)getIntv,獲取從當前時間到指定日期的間隔時間
題目:
var str = getIntv("2016-01-08");
console.log(str); // 距除夕還有 20 天 15 小時 20 分 10 秒


function getIntv(){
var nowTime = new Date()//目前的時間
var perTime = new Date("2016-10-01")
d = nowTime - perTime//console.log(d)得到兩者差的毫秒數(shù)
var perDay = 24*60*60*1000
perHour = 60*60* 1000
perMinute = 60*1000
var day = Math.floor(d/perDay)//得到今日到2016.10.01距離是0日
hour = Math.floor((d-day*perDay)/(perHour))//先相減得到剩余小時的毫秒數(shù)
minutes = Math.floor((d-(day*perDay+hour*perHour))/(60*1000))//總毫秒數(shù)-(足一天的天數(shù)+剩余的小時)之和的秒數(shù)
second = Math.floor((d-(day*perDay+hour*perHour+minutes*perMinute))/1000)//總毫秒數(shù)-(足一天的天數(shù)+剩余的小時+剩余的分鐘)之和的秒數(shù)
var result = "當前時間距離2016年10月01日:"+day+"天"+hour+"小時"+minutes+"分"+second+"秒";
console.log(result)
}
getIntv() //當前時間距離2016年10月01日:0天16小時15分7秒
留意:js里Date計算一天按每日的早上(AM)08:00才算是過了一天
4.把數(shù)字日期改成中文日期
題目:
var str = getChsDate('2015-01-08');
console.log(str); // 二零一五年一月八日
function getChsDate(str){
var dateMessage = {
"0": "零",
"1": "一",
"2": "二",
"3": "三",
"4": "四",
"5": "五",
"6": "六",
"7": "七",
"8": "八",
"9": "九",
"10": "十",
"11": "十一",
"12": "十二",
"13": "十三",
"14": "十四",
"15": "十五",
"16": "十六",
"17": "十七",
"18": "十八",
"19": "十九",
"20": "二十",
"21": "二十一",
"22": "二十二",
"23": "二十三",
"24": "二十四",
"25": "二十五",
"26": "二十六",
"27": "二十七",
"28": "二十八",
"29": "二十九",
"30": "三十",
"31": "三十一"
};
var newStr = str.split("-");//["2015","01","08"]
var year = newStr[0];
var month = newStr[1];
var date = newStr[2];
var yearConcat = dateMessage[year[0]]+dateMessage[year[1]]+dateMessage[year[2]]+dateMessage[year[3]],
monthConcat = dateMessage[Number(month)],
dateConcat = dateMessage[Number(date)];//01和10有區(qū)別,要用到Number強制轉(zhuǎn)換
var result = yearConcat+"年"+monthConcat+"月"+dateConcat+"日"
return result
}
console.log(getChsDate('2015-01-08'))//"二零一五年一月八日"
console.log(getChsDate('2016-10-02'))//"二零一六年十月二日"
5.寫一個函數(shù)獲取n天前的日期
題目:
var lastWeek = getLastNDays(7); // '2016-01-08'
var lastMonth = getLastNDays(30); // '2015-12-15'
function getLastNDays(n){
var nowTime = Date.now();
var setdate = n*24*60*60*1000;
var d = new Date(nowTime - setdate);//括號是得到毫秒數(shù),d則是CMT格式的時間
var year = d.getUTCFullYear();//UTC的API
var month = d.getUTCMonth();
var date = d.getUTCDate();
if(month < 10){
month = "0"+month;
}
if(date<10){
date = "0"+date
}
var result = year+"-"+month+"-"+date
return result;
}
var lastWeek = getLastNDays(7);
var lastMonth = getLastNDays(30);
console.log("距離現(xiàn)在時間按一個星期前的日期:"+lastWeek);
console.log("距離現(xiàn)在時間一個月前的日期:"+lastMonth);

6.完善如下代碼,用于獲取執(zhí)行時間如:
題目:
var Runtime = (function(){
//code here ...
var obj = {
start: function(){
//code here ..., 當前時間
},
end: function(){
//code here ... 結(jié)束時間
},
get: function(){
//code here ... 獲取執(zhí)行時間
}
};
return obj;
}());
Runtime.start();
//to do something
Runtime.end();
console.log( Runtime.get() );
測試一個for循環(huán)執(zhí)行要多少毫秒,計算機性能不同秒數(shù)不一樣

7.樓梯有200級,每次走1級或是2級,從底走到頂一共有多少種走法?用代碼(遞歸)實現(xiàn)
思路:
1.當走一級樓梯時,只有1種走法,
2.當走二級樓梯時,有2種走法;
3.當走三級樓梯時,要么從一級樓梯上跨2級,要么從二級樓梯上跨1級,所以,三級樓梯的走法是走一級樓梯的方法加上走二級樓梯的方法,即3種走法。
4.當走四級樓梯時,同樣的思路,要么從二級樓梯上跨2級,要么從三級樓梯上跨一級,所以,四級樓梯的走法是走二級樓梯的方法加上走三級樓梯的方法,即5種走法。
5.以此類推,n級樓梯的走法,就是走(n-2)級樓梯的方法加上走(n-1)級樓梯的方法。
function fn(n){
if(n===1){
return 1
}else if(n===2){
return 2
}
return fn(n-1)+fn(n-2)
}
console.log(fn(4)) //輸出5種走法
運行過程拆分
fn(4)
fn(3)+fn(2)
fn(2)+fn(1)+fn(3)
console.log(fn(200)); // 打印導(dǎo)致瀏覽器崩潰, 函數(shù)的堆棧溢出導(dǎo)致
簡單的說,堆和棧(主要是棧)是存在處理上限的,一旦需要待處理的函數(shù)
中的(局部變量,傳遞參數(shù),返回值等等)超過其上限后,計算機就罷工,瀏覽器崩潰。
所以解決這類由于遞歸出現(xiàn)的堆棧溢出的最好辦法就是即時釋放,即時用閉包法
6.寫一個json對象深拷貝的方法,json對象可以多層嵌套,值可以是字符串、數(shù)字、布爾、json對象中的任意項
var objList = {
name:"hunger",
age:18,
hobby:{
a:1,
b:2
}
};
//深拷貝
function deepCopy(obj){
var newObj = {};
for(var key in obj){
if(typeof obj[key] === "object"){//對象內(nèi)含對象再作判斷
newObj[key] = deepCopy(obj[key])//遞歸
}else{
newObj[key] = obj[key]
}
}
return newObj
}
console.log(deepCopy(objList))
console.log(deepCopy(objList) === objList);

//json對象可以多層嵌套
var objList = {
"name": "hunger",
"age": 18,
"sex": "man",
"local": {
'name': "China",
'number': 19
},
"hobby":['swim','run']
};
function deepCopy(obj){
var newObj = {};
for(var key in obj){
if(typeof obj[key] === "object"){
newObj[key] = deepCopy(obj[key])//遞歸
}else{
newObj[key] = obj[key]
}
}
return newObj
}
console.log(deepCopy(objList))
結(jié)果如下圖:

深拷貝的業(yè)務(wù)場景:就是想復(fù)制一份東西,但又不想改變原來被拷貝對象中的信息,同時不想和之前拷貝的東西有關(guān)聯(lián),那么就得用上深拷貝...另外因為淺拷貝會把引用地址給一并拷貝了,容易造成修改新配置時把坐標一并修改了,所以對象中如果還含有對象層級都建議用深拷貝