(一) css面试
1.盒子水平垂直居中
(五大方案)
-
定位:三种
- 前提:父盒子相对定位,子盒绝对定位
- [1]. 父盒子有固定宽高,在子样式中写出计算出的子盒子应该距离顶部和左边的距离
- [2]. 父盒子有固定宽高
.son{ position:absolute; top:0; left:0; right:0; bottom:0; margin: auto; }
- [3]. 问题:存在不兼容
position:absolute; top:50%; left: 50%; transform: translate(-50%,-50%);
-
display:flex 问题:不兼容
.father{ display: flex; justify-content: center; align-items: center; }
-
javascript 算出来
-
使用table-cell (原本是控制文本的,所以可以将子盒子设置为inline-block)
.father{ //需要有固定的宽高 //宽高不能是百分比 display:table-cell; vertical-align:middle; text-align:center; }
2.css3盒模型
- 标准盒模型(box-sizing:content-box)、怪异盒模型(ie盒模型)和flex弹性伸缩盒模型
3.几大经典布局方案
[1]. 圣杯布局
[2]. 双飞翼布局
4.移动响应式布局开发三大方案
- media
- rem
- flex
- vh / vw(类百分比)
- 百分比
5.课后作业
-
使用css,让一个div在视野中消失
1.position:absolute/relative/fixed + 方位 top/bottom/left/right: -9999px 2.display:none 3.visibility:hidden 4.width:0 + overflow:hidden height:0 + overflow:hidden 5.margin-top/bottom/left/right:-9999px; 6.background-color:transparent 7.opacity:0 8.transform: translateX(-9999px)/translateY(-9999px)/translate(-9999px,-9999px) 9.transform: scale(0)
-
请说明z-index的工作原理,适用范围
https://www.kancloud.cn/fining/htmlcssknowledgepoints/13230321.z-index这个属性控制着元素在z轴上的表现形式。 2.适用范围:仅适用于定位元素,即拥有relative,absolute,fixed属性的position元素。 3.堆叠顺序是当前元素位于z轴上的值,数值越大说明元素的堆叠1顺序越高,越靠近屏幕。 4.未定义时,后来居上,未定义z-index的属性,元素的堆叠顺序基于它所在的文档树。默认情况下,后来的元素的z-index的值越大。 5.使用范围: 1.网页两侧的浮动窗口(播放器,指定按钮,广告等) 2.导航栏浮动置顶 3.隐藏div实现弹窗功能(通过设置div定位和z-index控制div的位置和出现隐藏)
-
谈谈对html5的理解
优点:
1)多设备,跨平台;
2)用户体验好;
3)新标签的可读性高,有助于开发人员定义重要内容;
4)提供了更多的多媒体元素(视频和音频);
5)很好地替代了Flash和Silverlight;
6)涉及到网站的抓取和索引的时候,SEO更加友好;
7)可以被大量应用于移动应用程序和游戏。
缺点:
1)web storage和web socket这样的功能很容易被黑客利用,安全性差;
2)兼容性不好,很多浏览器的支持程度不一样;
3)有一定的技术门槛;
4)某些平台上的引擎问题导致HTML5性能低下;
-
如何使一个div里面的文字垂直居中,并且文字的大小根据屏幕大小自适应
https://www.cnblogs.com/moqiutao/p/4807792.html#articleHeader1
https://blog.csdn.net/liyede2008/article/details/78213054 -
下面哪个渲染性能高
.box a{
...
}
a{
...
}
(二) js面试
1.js的数据类型及区别
- 基础数据类型
number string boolean null undefine - 引用数据类型
Object、symbol
ES6 中新增了一种 Symbol 。这种类型的对象永不相等,即始创建的时候传入相同的值,可以解决属性名冲突的问题,做为标记。
object包含Data、function、Array等
2. 对象(数组)的深克隆和浅克隆
浅克隆
let obj = {
a: 100,
b: [10, 20, 30],
c: {
x: 10
},
d: /^\d+$/
};
function clone(obj){
let obj2= {
};
for(let key in obj){
//使用hasOwnProperty()方法来忽略继承属性。
if(!obj.hasOwnProperty(key)) break;
console.log(key);
obj2[key] = obj[key];
}
return obj2
}
var obj2= clone(obj);
obj2.a = 200;//基础数据类型,不会影响被克隆的数值
obj2.b[0] = 200;//引用类型会影响被克隆的数值
console.log(obj2);
console.log(obj);
深克隆
可以使用JSON.stringify()来实现深克隆,但是JSON.stringify()处理函数,时间(new Date()),正则表达式时会出问题。
let obj = {
a: 100,
b: [10, 20, 30],
c: {
x: 10
},
d: /^\d+$/
};
function deepClone(obj) {
if(obj === null) return null;
if (typeof obj !== 'object') return obj;
// instanceof 测试一个对象是否为一个类的实例
if(obj instanceof RegExp) return new RegExp(obj); //创建一个新实例,和原值引用不同的地址
if(obj instanceof Date) return new Date(obj);
//不直接创建空对象的目的:克隆的结果和obj保持相同的所属类
//比如:如果obj是一个实例,则new obj.constructor相当于new obj所属的类。
let cloneObj = new obj.constructor;
for(let key in obj){
if(obj.hasOwnProperty(key)){
cloneObj[key] = deepClone(obj[key]);
}
}
return cloneObj;
}
var obj2= deepClone(obj);
obj2.a = 200;
obj2.b[0] = 200;
console.log(obj2);
console.log(obj)
3.堆栈内存
//example 1
//字符串属性名和数字属性名相同时表示的是一个属性名
let a = {
}, b = '0', c = 0;
a[b] = '珠峰';
a[c] = '培訓';
console.log(b);
console.log(a[b]);
//example 2
//Symbol创建唯一值,即b !== c
let a = {
}, b = Symbol('1'), c = Symbol('1');
a[b] = '珠峰';
a[c] = '培訓';
console.log(b);
console.log(c);
console.log(a[b]);
//example 3
//对象存储引用类型值最后都会变为字符串进行存储
//在存储b对象时,会进行b.toString()操作,变为[objct, objct],存储c时也会进行toString()操作,变为[objct, objct],所以‘培训’会将‘珠峰’给覆盖掉
let a = {
} b = {
n:'1'}, c = {
m:'2'};
a[b] = '珠峰';
a[c] = '培訓';
console.log(b);
console.log(a[b]);
第一道题:
数组和对象的区别
- 数组表示有序数据的集合,而对象表示无序数据的集合。如果数据的顺序很重要,就用数组,否则就用对象。
数组和对象的另一个区别是,数组的数据没有”名称”(name),对象的数据有”名称”(name)。
4.闭包
返回字符串4
var test = (function(i){
return function(){
//alert弹出来的都是字符串
alert(i*2);
}
})(2);
test(5);
5.闭包2
var a = 0, b = 0;
function A(a){
A = function(b){
alert(a+b++);
}
alert(a++)
}
A(1);
A(2);
6.变量提升
变量提升就是(var和function声明的时代下)在当前作用域下,所有代码执行之前,把所有带var和function关键字提前声明和定义,带var的变量提前声明,带function的变量提前声明和定义
function Foo() {
getName = function () {
console.log(1);
};
return this;
}
Foo.getName = function () {
console.log(2);
}
Foo.prototype.getName = function () {
console.log(3);
}
var getName = function () {
console.log(4);
}
function getName() {
console.log(5);
}
Foo.getName();//2
getName();//4
Foo().getName();//1
getName();//1
new Foo.getName();//2
new Foo().getName();//3
new new Foo().getName();//3
- 同步异步
async function async1(){
console.log('async1 start');//2
await async2();
console.log('async1 end');//6
}
async function async2(){
console.log('async2');//3
}
console.log('script start'); //1
setTimeout(() => {
console.log('setTimeout'); //8
}, 0);
async1();
new Promise(function(resolve){
console.log('promise1');//4
resolve();
}).then(function(){
console.log('promise2');//7
});
console.log('script end');//5
7.call 和apply的区别是什么,哪个性能更好一些
bind的this指向不会立即执行
call 和apply都是function原型上的方法,每一个函数都是function原型上的实例,可以调用原型上的call和apply,call和apply都是改变函数中的this指向,唯一的区别就是call是一个个传递参数,apply是传递一个数组
fn.call(obj, 10,20,30)
fn.apply(obj, [10,20,30])
参数超过三个,call比apply性能高一点。
后期开发的时候,可以使用call多点
//测试代码执行时间
console.time('A');
//代码
console.timeEnd('A');
8.实现(5).add(3).minus(2),使其结果为6
~ function () {
function check(n) {
//将传递进来的n转换为数字,如果是一个非有效数字 n==NaN
n = Number(n);
return isNaN(n) ? 0 : n;
}
function add(n) {
n = check(n)
return this + n;
}
function minus(n) {
n = check(n)
return this - n;
}
Number.prototype.add = add;
Number.prototype.minus = minus;
}();//这里的分号要写
console.log( (5).add(3).minus(2));
9. 给英文单词前后加空格
let str = 'no作no死,you can you 上',
reg = /\b\w+\b/ig;
as = str.replace(reg, function (value) {
return ' ' + value + ' ';
}).trim();
console.log(as);
10. 箭头函数与普通函数(function)的区别是什么?构造函数(function)可以使用new生成实例,那么箭头函数可以吗?为什么?
- 区别:
1.箭头函数语法上比普通函数更加简洁
2.箭头函数没有自己的this,它里面出现的this从属于函数所处的上下文中的this(使用call/apply等任何方式都无法改变this的指向)funtion fn(x){ return function(y){ return x + y } } let fn = x=> y => x + y;
let obj = { name:'obj' } function fn1(){ console.log(this); } fn1.call(obj); let fn2 = ()=>{ console.log(this) } fn2.call(obj)
3.this的指向
//箭头函数外边没有其他函数包围,一般指向window(自己想的)
document.body.onclick = ()=>{
//=>this为window 而不是body
}
document.body.onclick = function (){
//=>this为body
arr.sort(function (a,b){
//this为window,而不是arr或者sort,因为sort只是执行了当前函数,回调函数中的this,一般指向window
})
}
- 箭头函数中没有arguments,
- 箭头函数不能被new(因为箭头函数没有this也没有prototype)
11. 字符串大小写取反,例如‘AbC’变为‘aBc’
let str = "asdfSDNSFNdsfafas;找房"
//content是匹配到的字符
str = str.replace(/[a-zA-Z]/g, content=>{
//str.charCodeAt() 获取字符的ASCII码
return content.toUpperCase() === content ? content.toLowerCase() : content.toUpperCase();
})
console.log(str);
12. 在一个字符串中查到另一个方法,返回其位置,不存在返回-1,不能用indexof
let str1 = 'wangwendong';
let str2 = 'wen';
console.log(str1.indexOf(str2));
String.prototype.myIndexOf = function myIndexOf(str2) {
//this就是str1
console.log(this);
let str1Length = this.length;
let str2Length = str2.length;
if(str1Length< str2Length){
return -1;
}
for (let i = 0; i <= str1Length - str2Length; i++){
let empstr = this.substr(i,str2Length);
if(empstr === str2){
return i;
}
}
return -1;
}
console.log(str1.myIndexOf(str2));
//z正则
String.prototype.myIndexOf2 = function (str2){
let reg = new RegExp(str2);
let res = reg.exec(this);
return res === null ? -1 : res.index;
}
console.log(str1.myIndexOf(str2));
12. 引用变量
//对象中数字属性名123和字符串属性名'123'表示的是同一个
//即a[123] == a['123']
var a={
}, b='123',c=123;
a[b] = 'b';
a[c] = 'c'
console.log(a[b]);
//Symbol创建的值是唯一的
var a = {
}, b = Symbol('123'), c=Symbol('123');
a[b] = 'b';
a[c] = 'c';
console.log(a[b]);
//对象的属性名不能是引用类型,会自动将引用类型变为字符串类型
//({key:'123'}).toString() 转换为字符串 '[Object,Object]',
//[1,2,3].toString()转换为字符串 '1,2,3'
var a ={
}, b = {
key:'123'}, c={
key:'456'}
a[b] = 'b';
a[c] = 'c';
console.log(a[b]);
13. 验证url
let url = 'https://www.baidu.com:80/index.html?name=zhang&age=12#search';
let reg = /^((http|https|ftp):\/\/)?([\w-]+\.)+([a-z0-9])+(:(\d)+)?((\/[^/?#]*)+)?(\?[^?#]+)?(#.+)?$/i;
console.log(reg.exec(url));
14. 函数的三种角色
function Foo(){
Foo.a = function(){
console.log(1);
}
this.a = function (){
console.log(2);
}
}
//讲Foo当做类,在原型上设置实例共有的属性方法 调用:实例.a()
Foo.prototype.a = function(){
console.log(3);
}
//将Foo当做普通对象设置私有的属性方法 调用:Foo.a()
Foo.a = function (){
console.log(4);
}
Foo.a();//4 调用它的时候,没有调用构造函数Foo
let obj = new Foo();//调用了构造函数Foo,foo.a 输出1
obj.a();//2
Foo.a();
15. 图片懒加载
- 前端性能优化的重要方案
1). 通过图片的延时或者数据的延迟加载,我们可以加快页面的渲染速度,让第一次打开页面的速度变快
2). 只有滑动到某个区域,我们才加载真实的图片,这样也可以节省加载的流量 - 处理方案
1). 所有需要延迟加载的图片用一个盒子包起来,设置宽高和默认占位图
2). 开始让所有的src为空,把真实图片的地址放到img的自定义属性上,让img隐藏等到所有其他资源都加载完成后,我们再开始加载图片
3). 对于很多图片,需要当页面滚动的时候,当前图片区域完全显示出来后再加载真实图片
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>图片延迟加载</title>
<style>
* {
padding: 0;
margin: 0;
}
.container {
width: 100%;
}
.img_box {
width: 215px;
height: 215px;
background-color: gray;
margin: 0 auto 10px;
}
.img_box img {
width: 100%;
display: none;
}
</style>
</head>
<body>
<div class="container">
<div class="img_box">
<img src="" alt="" data-link="https://cn.vuejs.org/images/logo.png">
</div>
</div>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script>
let $window = $(window);
let $container = $(".container");
//创建20个img_box
let str = '';
new Array(20).fill(null).forEach((item, index) => {
str +=
'<div class="img_box"><img src="" alt="" data-link="https://cn.vuejs.org/images/logo.png"></div>';
});
$container.html(str);
let $imgBoxArr = $(".img_box");
$window.on('load scroll', function () {
$imgBoxArr.each((index, item) => {
let $item = $(item);
if ($item.attr('data-load') === 'true') return;
//图片距离顶部的距离
let $imgPosition = $item.offset().top + $item.outerHeight();
let $srceenPosition = $window.outerHeight() + $window.scrollTop();
if ($imgPosition < $srceenPosition) {
let $img = $item.children();
$img.attr('src', $img.attr('data-link'));
$img.on('load', function () {
//$img.css('display', 'block')
$img.stop().fadeIn();
//data-load设置的值为字符串true
$img.parent().attr('data-load', true)
})
}
})
})
</script>
</body>
</html>
15. 正向预查
(?=pattern)正向预查:/cainiao(?=8)/ 只能匹配cainiao8中的cainiao,而不能匹配cainiao9中的cainiao,也不能匹配cainiao
(?!pattern)负向预查:必须不满足pattern这个条件。/cainiao(?!8)/能匹配cainiao
一个6~16位的字符串,必须同时包含有大小写字母和数字
//(?!^[a-zA-Z]+$) 非小写字母,非大写字母,非大小写字母混合
//(?!^[0-9a-z]+$) 非小写字母,非数字,非大小写字母混合
console.log(/(?!^[a-zA-Z]+$)(?!^[0-9A-Z]+$)(?!^[0-9a-z]+$)^[0-9a-zA-Z]{6,16}$/.test('123Asad'));
16. 根据属性名和属性值返回元素
写一个方法,输入属性名和属性值返回返回所有符合的元素
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div class="box con"></div>
<div class="time" id="box"></div>
<div class="conbox"></div>
<div class="t"></div>
<div data-src="baidu"></div>
<div class="box"></div>
<script>
function $attr(attr, value) {
//获取所有子节点,得到object
//let children =document.body.children;
let children = document.getElementsByTagName('*')
let arr = [];
//将object转换为数组
children = Array.from(children);
children.forEach(item => {
//获取属性值
let itemValue = item.getAttribute(attr);
if (itemValue === value) {
arr.push(item);
}else if(attr === 'class'){
//判断class 为 box con的情况
new RegExp('\\b'+value+'\\b').test(itemValue) ? arr.push(item) : '';
}
});
return arr;
}
console.log( $attr('class', 'box'));
</script>
</body>
</html>