说一说你理解的css盒模型,以及如何在css中告诉不同的盒模型来渲染布局。
答:有两种。一种是w3c的标准盒模型:盒子所占宽(高) = 设置的width(height) + margin + padding + border。一种是IE盒模型:盒子所占宽(高)= 设置width(height) + margin。因为设置的width = content + padding + border。
使用css3中的box-sizing属性,分别对应:conten-box和border-box。JS有哪些数据类型,深复制,复制机制,参数传递机制。
答:五中基本类型:number,string,Boolean,null,undefined。一种引用类型:object。ES6新增的symbol。
深拷贝:
var deepClone = (obj)=>{
if(obj instanceof Object){
var newObj = obj.constructor === Object ? {} : [];
for(let key in obj){
if(typeof obj[key] != "object" || typeof obj[key] == null){
newObj[key] = obj[key];
}else{
newObj[key] = deepClone(obj[key]);
}
}
}else{
return obj;
}
return newObj;
}
ES6的Object.assign(目标对, 源对象1, 源对象2...);方法。可以实现对对象中基本类型的拷贝,但引用类型依旧是浅拷贝。
var obj1 = { name:"111", age:32, child:{ name:"221", age:2} }
var obj2 = Object.assign( {}, obj1);
obj2; //{name: "111", age: 32, child:{ name:"221", age:2}}
obj2.name = "222";
obj2.age = 33;
obj2.child.age = 3;
obj2; //{name: "222", age: 33, child:{ name:"221", age:3}}
obj1; //{name:"111", age:32, child:{ name:"221", age:3}}
var obj3 = obj1; //es5中普通浅拷贝
obj3; //{name: "111", age: 32, child:{ name:"221", age:3}}
obj3.name = "333";
obj3.child.age = 4;
obj3 === obj1; // true
obj2; //{name: "222", age: 33, child:{ name:"221", age:4}}
对象是堆存储,复制对象时并不会在堆内存中新生成一个相同的对象,只是多了一个保存指向这个对象指针的变量罢了。
再看参数传递机制:
var person = {
name : "Tom"
};
function foo(peo){
peo.name = "Jerry";
return peo;
}
var result = foo(person);
console.log(result.name);// Jerry
console.log(person.name);// Jerry
在该例子中,把person复制传入foo()中,peo和person指向了同一个对象,而在peo中修改了name属性,其实修改了它们共同指向的对象的name属性。
var person = {
name : "Tom"
};
function foo2(peo){
peo = {
name : "Jerry"
};
return peo;
}
var result = foo2(person);
console.log(result.name);// Jerry
console.log(person.name);// Tom
上面例子中,在函数中重新定义了一个对象,也就是现在堆内存中有两个对象,所以调用后返回的值是新定义的对象的值。如果是参数是按引用传递的,那么person.name打印出来的结果为Jerry,从这点可以得出参数是按值传递的(有的地方叫做按共享传递)。
总结:函数的参数是值传递,对象类型作为参数的时候传递的是地址(指针)的值,而不是对象本身堆内存中的value。所以在函数内部用参数去修改对象,那么查找到的还是原对象,因为指向相同,所以原对象也受影响。如果新实例化一个对象赋值给该指针,那么指针指向的就是一个全新的对象了,和原来指向的对象失去联系。
- 下面两段代码段的输出分别是什么?(作用域,闭包)
var scope = "global";
function checkscope(){
var scope = "local";
function f(){
return scope;
}
return f();
}
checkscope();
var scope = "global";
function checkscope1(){
var scope = "local";
function f(){
console.log(scope);
}
return f;
}
checkscope1()();
答:都是“local”。都是闭包的使用。
- 前后端如何通信,标签页如何通信。
答:http请求。分析get与post的区别,以及如何让get安全请求?
最直观的区别就是:
1、GET把参数包含在URL中,POST通过request body传递参数。
2、GET在浏览器回退时是无害的,而POST会再次提交请求。
3、GET产生的URL地址可以被Bookmark,而POST不可以。
4、GET请求会被浏览器主动cache,而POST不会,除非手动设置。
5、GET请求的参数会完整的被保存在历史记录里,POST不会。
6、GET请求只能进行url编码,POST请求支持多种编码方式。
7、对于参数类型,GET只接受ASCII字符,而POST没有限制。
8、GET请求在URL中传递的参数是有长度限制的,而POST没有。
9、GET比POST更不安全,因为参数直接暴露在URL中,所以不能传递敏感信息。
GET产生一个TCP数据包;POST产生两个TCP数据包。
对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据); 而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。
标签页通信:cookie,localStorage,sessionStorage
什么是同源政策,你平时是如何解决跨域的。
答:同源:域名,协议(http),端口都相同。 同源政策目的:保证用户信息的安全,防止恶意的网站窃取数据。
浏览器同源政策及其规避方法--阮一峰
跨域全面介绍,超详细你理解的Promise。
说一下你理解的函数节流和函数防抖(去抖),以及他们的应用场景。
答:函数节流(throttle):是让一个函数无法在很短的时间间隔内连续调用,当上一次函数执行后过了规定的时间间隔,才能进行下一次该函数的调用。
// 函数节流
var canRun = true;
document.getElementById("throttle").onscroll = function(){
if(!canRun){
// 判断是否已空闲,如果在执行中,则直接return,取消这次方法执行
return;
}
canRun = false;
setTimeout(function(){
console.log("函数节流");
canRun = true;
}, 300);
};
函数去抖(debounce):让一个函数在一定间隔内没有被调用时,才开始执行被调用方法。两个方法都是用来提升前端性能,减轻浏览器压力。
// 函数防抖
var timer = false;
document.getElementById("debounce").onscroll = function(){
clearTimeout(timer); // 清除未执行的代码,重置回初始化状态
timer = setTimeout(function(){
console.log("函数防抖");
}, 300);
};
JavaScript函数节流和函数防抖之间的区别
Javascript函数节流与函数去抖
call和apply的区别和作用,以及如果让你模拟实现call函数你会怎么实现?
答:他们都可以显示的改变函数执行上下文this的指向。区别在于参数传递不同。apply只接受两个参数,第二个是数组或者类数组的形式。
call,apply,bind的三种原生实现方法了解vue,react,angular吗?什么是前端工程化,内涵是什么?
答:一个完整的前端工程体系应该包括:1)统一的开发规范;2)组件化开发;3)构建流程。
参考: 浅谈什么是前端工程化下面的代码输出是什么?
console.log(1)
setTimeout(()=>{
console.log(2)
new Promise(resolve=>{
console.log(4)
resolve()
}).then(()=>{
console.log(5)
})
},1)
new Promise(resolve=>{
console.log(7)
resolve()
}).then(()=>{
console.log(8)
})
setTimeout(()=>{
console.log(9)
new Promise(resolve=>{
console.log(11)
resolve()
}).then(()=>{
console.log(12)
})
},0)
结果:1 7 8 2 4 5 9 11 12
- 以下代码输出什么?
setTimeout(function() {
console.log(1)
}, 0);
console.log(6);
new Promise(function executor(resolve) {
console.log(2);
for( var i=0 ; i<10000 ; i++ ) {
i == 9999 && resolve();
}
console.log(3);
}).then(function() {
console.log(4);
});
console.log(5);
结果:6 2 3 5 4 1
这道题应该考察我 JavaScript 的运行机制的。首先先碰到一个 setTimeout,于是会先设置一个定时,在定时结束后将传递这个函数放到任务队列里面,因此开始肯定不会输出 1 。 然后肯定是直接输出6,然后是一个 Promise,里面的函数是直接执行的,因此应该直接输出 2 3 。 然后,Promise 的 then 应当会放到当前 tick 的最后,但是还是在当前 tick 中。 因此,应当先输出 5,然后再输出 4 。 最后在到下一个 tick,就是 1 。
瀑布流布局及其实现。
多列布局。
相关知识点:
箭头函数:
function getNum(num,callBack){
let result = num + 1;
callBack(result)
}
getNum(1,function(result){
console.log(result)
})//2
其实对getNum的调用可以使用:
getNum(1,res=> console.log(res)); /2
箭头函数不绑定自己的this,arguments,super或 new.target。其this一旦定义后就不更改,箭头函数中的 this妥妥的指向了这个对象,跟谁调用它完全无关。
var name = "outer"
var obj = {
name : "inner",
getName : function(){
return function(){
console.log(this.name)
}
},
getNameByArrow : function(){
return () => console.log(this.name)
}
}
obj.getName()(); //outer
obj.getNameByArrow()(); //inner
setTimeout(当时间设置为0和1时,可以忽略,还是顺序执行)
1:
console.log(1)
setTimeout(()=>{
console.log(2)
},1)
console.log(3)
setTimeout(()=>{
console.log(4)
},0)
输出:1 3 2 4
2:
console.log(1)
setTimeout(()=>{
console.log(2)
},2)
console.log(3)
setTimeout(()=>{
console.log(4)
},0)
输出:1 3 4 2
3:
console.log(1);
new Promise(resolve=>{
console.log(7)
resolve()
}).then(()=>{
console.log(8)
});
console.log(2);
输出:1 7 2 8