前端面试题合集1-5
(浏览器缓存方式,js数据类型详解,闭包详解,Promise解析,跨域以及解决方式详解):https://editor.csdn.net/md/?articleId=125893677
BFC(Block Formatting Context)块级格式化上下文,是Web页面一块独立的渲染区域,内部元素的渲染不会影响边界以外的元素。
BFC布局规则 :
内部盒子会在垂直方向,一个接一个地放置。(其实就是block元素布局规则)
如下图所示:
Box垂直方向的距离由margin决定,属于同一个BFC的两个相邻Box的margin会发生重叠。
什么是边距重叠?举个栗子:
<style>
.bfc {
/* 让它成为BFC元素 */
overflow: hidden;
background-color: pink;
}
.child1,
.child2 {
width: 200px;
height: 200px;
}
.child1 {
background: #678;
/* 设置了下边距 */
margin-bottom: 10px;
}
.child2 {
background-color: #09f;
/* 设置了上边距 */
margin-top: 10px;
}
style>
head>
<body>
<div class="bfc">
<div class="child1">div>
<div class="child2">div>
div>
body>
按道理应该显示10+10 =20px,而实际并非如此,从下图可以看到,实际上的间距只有10px,另外10px被吞掉了,这就是高度塌陷。解决办法就是利用两个独立的BFC容器,将它们包裹起来,如下所示:
<style>
.bfc1,
.bfc2 {
/* 设置两个独立的bfc */
overflow: hidden;
background-color: pink;
}
.c1,
.c2 {
width: 200px;
height: 200px;
}
.c1 {
background: #678;
/* 设置下边距 */
margin-bottom: 10px;
}
.c2 {
background-color: #09f;
/* 设置上边距 */
margin-top: 10px;
}
style>
head>
<body>
<div class="bfc1"><div class="c1">div>div>
<div class="bfc2"><div class="c2">div>div>
body>
如下图:两个盒子都是紧紧贴BFC容器的边框,即使盒子2设置的是浮动元素(float:right)也符合这个规则。
<style>
.parent {
border: 1px solid red;
}
.c1 {
width: 100px;
height: 100px;
background-color: pink;
float: left;
}
style>
head>
<body>
<div class="parent">
<div class="c1">盒子1div>
div>
body>
从上图可以明显看到父元素的高度塌陷了,这时需要通过清除浮动来使得高度显示正常。
而BFC元素默认清除其子元素的浮动。
于是我们可以:
我们就可以看到高度塌陷问题得到了解决,如下图:
float
设置成 left
或 right
position
是absolute
或者fixed
overflow
不是visible
,为 auto
、scroll
、hidden
display
是flex
或者inline-block
等 。overflow:hidden
,原因是使用float或者position方式清除浮动,虽然父级盒子内部浮动被清除了,但是父级本身又脱离文档流了,会对父级后面的兄弟盒子的布局造成影响。如果设置父级为display:flex
,内部的浮动就会失效。所以通常只是用overflow: hidden
清除浮动。了解边界重叠(高度塌陷)与BFC关系:
https://segmentfault.com/a/1190000012265930
https://juejin.cn/post/7029622804739784717
JavaScript有4
种方法判断变量的类型,分别是:
typeof
instanceof
Object.prototype.toString.call()
(对象原型链判断方法)
constructor
(用于引用数据类型)
常用于判断基本数据类型
,对于引用数据类型除了function返回’function‘,其余全部返回’object’。
这里值得注意的是typeof null 返回的也是object
null作为一个基本数据类型为什么会被typeof运算符识别为object类型呢? 这是因为javascript中不同对象在底层都表示为二进制,而javascript 中会把二进制前三位都为0的判断为object类型,而null的二进制表示全都是0,自然前三位也是0,所以执行typeof时会返回’object。
具体案例(用法):
const num1 = 1;
const str1 = "icyakuya";
const comicList = ["凡人修仙传", "斗破苍穹", "吞噬星空"];
const big = BigInt(999999999999999999999999999999999);
const symbol = Symbol("icy");
const happyDay = {
play: "出去玩",
game: "打电动",
eatting: "吃好吃的",
sleepping: "睡到自然醒",
};
const myFunc = () => {
return "icygodlike";
};
/* 基本数据类型 */
console.log(typeof num1); // number
console.log(typeof str1); //string
console.log(typeof undefinded); //undefinded
console.log(typeof null); //object
console.log(typeof true); //boolean
console.log(typeof big); //bigInt
console.log(typeof symbol); //symbol
/* 函数 */
console.log(typeof myFunc); //function
/* 引用数据类型 */
console.log(typeof comicList); //object
console.log(typeof happyDay); //object
输出的结果按顺序依次如下:
主要用于区分引用数据类型
,检测方法是检测的类型在当前实例的原型链上,用其检测出来的结果都是true,不太适合用于简单数据类型的检测
,检测过程繁琐且对于简单数据类型中的undefined, null, symbol检测不出来。
具体案例(用法):
/*无法用来检测基本数据类型*/
console.log(num1 instanceof Number); //false
console.log(str1 instanceof String); //false
//boolean, null ,undefinded ,bigInt ,symbol 数据类型均无法检测
/* 引用数据类型 */
console.log(myFunc instanceof Function); //true
console.log(myFunc instanceof Object); //true
console.log(comicList instanceof Array); //true
console.log(comicList instanceof Object); //true
console.log(happyDay instanceof Object); //true
注意点:可以看到,函数myFunc既是函数又是对象,comicList既是数组又是对象,这里涉及到原型链的问题,不了解的可以去学习js原型链相关概念。
instanceof的实现原理:
验证当前类的原型prototype是否会出现在实例的原型链__proto__上,只要在它的原型链上,则结果都为true。因此,instanceof
在查找的过程中会遍历左边变量的原型链,直到找到右边变量的 prototype
,找到返回true,未找到返回false。
想深入了解可以参考MDN官方介绍:
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/instanceof
用于检测引用数据类型
,检测方法是获取实例的构造函数判断和某个类型是否相同,如果相同就说明该数据是符合那个数据类型的,这种方法不会把原型链上的其他类也加入进来,避免了原型链的干扰。
用法案例
/* 引用数据类型 */
console.log(myFunc.constructor); // [Function:Function]
console.log(comicList.constructor); // [Function:Array]
console.log(happyDay.constructor); //[Function:Obejct]
console.log(myFunc.constructor === Function); // true
console.log(comicList.constructor === Array); // true
console.log(happyDay.constructor === Object); //true
注意点,constructor可能会被继承影响,而instanceof不会,具体如下:
function A() {}
function B() {}
const a = new A();
B.prototype = new A(); //让B继承自A
const b = new B(); //创建B是实例
console.log(a.constructor); //[Function:A]
console.log(b.constructor); // [Function:A] 可见,继承会影响constructor的判断,让它的类型指向父类
console.log(b instanceof A); //true
console.log(b instanceof B); //true 可见instanceof 并没有被继承影响
//解决方案,让b的constructor手动指向B
b.constructor = B;
console.log(b.constructor); //[function: B]
适用于所有类型的判断检测,检测方法是Object.prototype.toString.call(数据) 返回的是该数据类型的字符串。
Object.prototype.toString.call()原理
Object.prototype.toString 返回一个对象类型的字符串,call()方法可以改变this的指向,那么把Object.prototype.toString()方法指向不同的数据类型上面,返回不同的结果
用法示例:
const num1 = 1;
const str1 = "icyakuya";
let unknown; //undefinded
const comicList = ["凡人修仙传", "斗破苍穹", "吞噬星空"];
const big = BigInt(999999999999999999999999999999999);
const symbol = Symbol("icy");
const happyDay = {
play: "出去玩",
game: "打电动",
eatting: "吃好吃的",
sleepping: "睡到自然醒",
};
const myFunc = () => {
return "icygodlike";
};
const date = new Date(); //日期
function A() {} //构造函数
const a = new A(); //构造函数实例
console.log(Object.prototype.toString.call(num1)); //[object Number]
console.log(Object.prototype.toString.call(num1) === "[object Number]"); //true
console.log(Object.prototype.toString.call(str1)); // [objec String]
console.log(Object.prototype.toString.call(str1) === "[object String]"); //true
console.log(Object.prototype.toString.call(unknown)); //[objec Undefinded]
console.log(Object.prototype.toString.call(null)); //[objec Null]
console.log(Object.prototype.toString.call(comicList)); //[objec Array]
console.log(Object.prototype.toString.call(big)); //[objec BigInt]
console.log(Object.prototype.toString.call(symbol)); //[objec Symbol]
console.log(Object.prototype.toString.call(happyDay)); //[objec Object]
console.log(Object.prototype.toString.call(myFunc)); //[objec Function]
console.log(Object.prototype.toString.call(date)); //[objec Date]
console.log(Object.prototype.toString.call(A)); //[objec Function]
console.log(Object.prototype.toString.call(a)); //[objec Object]
输出结果:
总结: 这四种判断数据类型的方法中,各种数据类型都能检测且检测精准的就是Object.prototype.toString.call()
这种方法。
!important
注意点:
使用!important要谨慎 ,一定要优先考虑使用样式规则的优先级来解决问题而不是 !important
1)只有在需要覆盖全站或外部 CSS 的特定页面中使用 !important
2)永远不要在你的插件中使用 !important
3)永远不要在全站范围的 CSS 代码中使用 !important
优先级的比较指的是相同的样式属性,不同样式属性优先级比较失效,比如:在设置max-width
时注意,已经给元素的max-width
设置了!important
但是还不生效,很有可能就是被width覆盖了。
举例:div
最终的宽度还是200px
div {
max-width: 400px !important;
height: 200px;
background-color: tomato;
width: 200px;
}