1.基础类型有哪些?复杂类型有哪些?有什么特征?
- 基础数据类型:指的是简单的数据段
- 在JavaScript中有五种基本数据类型:undefined、null、boolean、number和string。
- 解析:基础类型是保存在栈内存中的简单数据段。通过变量复制基础类型值的时候,会建立新的内存并在新内存中保存相同的值。修改新的变量值不会影响被复制的变量值。
var a ="hello"
var b = a
a = "hi"
console.log(b)//"hello"
console.log(a)//"hi"
- 复杂类型:指的是由多个值构成的对象,包括:对象、函数、Date对象、数组、正则等
- 解析:复杂类型也属于引用类型。对象作为引用类型,实际上是保存在堆内存中。而变量中保存的是指向对象所在内存位置的指针。通过变量复制对象的时候,新变量的指针指在相同的内存位置。所以通过新变量修改数值的时候,被复制的变量所指向的值也会相应改变。
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}
基础类型和复杂类型的特征
(1)基础类型的特征是存储在栈内存中,按值访问,可以操作存储在变量中的实际的值
(2)复杂类型的特征是存储在堆内存中,按指针访问,操作复杂类型的对象时实际上是操作对象的引用(指针),而非实际的对象介绍一下JavaScript的内存机制
JavaScript中的内存分为栈内存和堆内存。
栈内存:先进后出,寄存速度快,栈数据可共享,由系统自动分配,数据固定不够灵活,空间大小有限制,超出则栈溢出。
堆内存:顺序随意,寄存速度比栈内存慢,由程序申请,操作简单,储存空间大(取决于系统有效虚拟内存)
基本数据类型分为变量标识和值,均保存在栈内存,变量标识指向其对应的值。
引用数据类型相对较为复杂,分为值、值所在堆地址以及变量标识,其中值保存在堆内存中,变量标识和值所在堆地址保存在栈内存,变量标识指向其对应的值所在堆地址。
参考(必看)Js内存机制详解
2.如下代码的输出? 为什么?
var obj1 = {a:1, b:2};
var obj2 = {a:1, b:2};
console.log(obj1 == obj2);//false 因为是两个不同的对象,跟它们的值相同没什么关系。
console.log(obj1 = obj2);//var obj1 = {a:1,b:2} //将obj2赋值给obj1。这时obj1指向obj2内存中对象的值。
console.log(obj1 == obj2);//true 上面那个操作让两者指向同一引用地址了,所以是true
3.写一个函数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)得到两者差的毫秒数
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))//先相减得到剩余小时的毫秒数
minutes = Math.floor((d-(day*perDay+hour*perHour))/(60*1000))//总毫秒数-(足一天的天数+剩余的小时)之和的秒数
second = Math.floor((d-(day*perDay+hour*perHour+minutes*perMinute))/1000)//总毫秒数-(足一天的天数+剩余的小时+剩余的分钟)之和的秒数
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.把数字日期改成中文日期
题目:
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有区别,要用到Number强制转换
var result = yearConcat+"年"+monthConcat+"月"+dateConcat+"日"
return result
}
console.log(getChsDate('2015-01-08'))//"二零一五年一月八日"
console.log(getChsDate('2016-10-02'))//"二零一六年十月二日"
5.写一个函数获取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);//括号是得到毫秒数,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("距离现在时间按一个星期前的日期:"+lastWeek);
console.log("距离现在时间一个月前的日期:"+lastMonth);
6.完善如下代码,用于获取执行时间如:
题目:
var Runtime = (function(){
//code here ...
var obj = {
start: function(){
//code here ..., 当前时间
},
end: function(){
//code here ... 结束时间
},
get: function(){
//code here ... 获取执行时间
}
};
return obj;
}());
Runtime.start();
//to do something
Runtime.end();
console.log( Runtime.get() );
测试一个for循环执行要多少毫秒,计算机性能不同秒数不一样
7.楼梯有200级,每次走1级或是2级,从底走到顶一共有多少种走法?用代码(递归)实现
思路:
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)); // 打印导致浏览器崩溃, 函数的堆栈溢出导致
简单的说,堆和栈(主要是栈)是存在处理上限的,一旦需要待处理的函数
中的(局部变量,传递参数,返回值等等)超过其上限后,计算机就罢工,浏览器崩溃。
所以解决这类由于递归出现的堆栈溢出的最好办法就是即时释放,即时用闭包法
6.写一个json对象深拷贝的方法,json对象可以多层嵌套,值可以是字符串、数字、布尔、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"){//对象内含对象再作判断
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))
结果如下图:
深拷贝的业务场景:就是想复制一份东西,但又不想改变原来被拷贝对象中的信息,同时不想和之前拷贝的东西有关联,那么就得用上深拷贝...另外因为浅拷贝会把引用地址给一并拷贝了,容易造成修改新配置时把坐标一并修改了,所以对象中如果还含有对象层级都建议用深拷贝