2018阿里前端面试总结(有详细解答)
2018阿里巴巴前端面试
(1)使用CSS实现一个持续的动画效果
部分代码:
animation: zz 5s infinite;
@keyframes zz {
from { left: 0px }
to { left: 100px }
主要考察animation的用法:
- animation-name——>规定需要绑定到选择器的keyframe名称
- animation-duration——>规定完成动画所花费的时间,以秒或毫秒计
- animation-timing-function——>规定动画的速度曲线
- animation-delay——>规定在动画开始之前的延迟
- animation-iteration-count——>规定动画应该播放的次数
- animation-direction——>规定是否应该轮流 反向播放动画
全部代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css"> * { padding: 0; margin: 0; } div { width: 100px; height: 100px; background-color: red; position: absolute; animation: zz 5s infinite; } @keyframes zz { from { left: 0px } to { left: 100px } } </style>
</head>
<body>
<div></div>
</body>
</html>
(2):使用JS实现一个持续的动画效果
给的答案是:requestAnimationFrame
- 与setTimeout和setInterval不同,requestAnimationFrame不需要设置时间间隔。
- HTML5新增的定时器requestAnimationFrame
- 计时器一直是javascript动画的核心技术。而编写动画循环的关键是要知道延迟时间多长合适。一方面,循环间隔必须足够短,这样才能让不同的动画效果显得平滑流畅;另一方面,循环间隔还要足够长,这样才能确保浏览器有能力渲染产生的变化
- 大多数电脑显示器的刷新频率是60Hz,大概相当于每秒钟重绘60次。大多数浏览器都会对重绘操作加以限制,不超过显示器的重绘频率,因为即使超过那个频率用户体验也不会有提升。因此,最平滑动画的最佳循环间隔是1000ms/60,约等于16.6ms
- 而setTimeout和setInterval的问题是,它们都不精确。它们的内在运行机制决定了时间间隔参数实际上只是指定了把动画代码添加到浏览器UI线程队列中以等待执行的时间。如果队列前面已经加入了其他任务,那动画代码就要等前面的任务完成后再执行
- requestAnimationFrame采用系统时间间隔,保持最佳绘制效率,不会因为间隔时间过短,造成过度绘制,增加开销;也不会因为间隔时间太长,使用动画卡顿不流畅,让各种网页动画效果能够有一个统一的刷新机制,从而节省系统资源,提高系统性能,改善视觉效果
特点:
- requestAnimationFrame会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率
- 在隐藏或不可见的元素中,requestAnimationFrame将不会进行重绘或回流,这当然就意味着更少的CPU、GPU和内存使用量
- requestAnimationFrame是由浏览器专门为动画提供的API,在运行时浏览器会自动优化方法的调用,并且如果页面不是激活状态下的话,动画会自动暂停,有效节省了CPU开销
使用:
requestAnimationFrame的用法与settimeout很相似,只是不需要设置时间间隔而已。requestAnimationFrame使用一个回调函数作为参数,这个回调函数会在浏览器重绘之前调用。它返回一个整数,表示定时器的编号,这个值可以传递给cancelAnimationFrame用于取消这个函数的执行
requestID = requestAnimationFrame(callback);
//控制台输出1和0
var timer = requestAnimationFrame(function(){
console.log(0);
});
console.log(timer);//1
cancelAnimationFrame方法用于取消定时器
//控制台什么都不输出
var timer = requestAnimationFrame(function(){
console.log(0);
});
cancelAnimationFrame(timer);
也可以直接使用返回值进行取消
var timer = requestAnimationFrame(function(){
console.log(0);
});
cancelAnimationFrame(1);
IE9-浏览器不支持该方法,可以使用setTimeout来兼容
简单兼容:
if (!window.requestAnimationFrame) {
requestAnimationFrame = function(fn) { setTimeout(fn, 17); }; }
严格兼容:
if(!window.requestAnimationFrame){
var lastTime = 0;
window.requestAnimationFrame = function(callback){
var currTime = new Date().getTime();
var timeToCall = Math.max(0,16.7-(currTime - lastTime));
var id = window.setTimeout(function(){
callback(currTime + timeToCall);
},timeToCall);
lastTime = currTime + timeToCall;
return id;
}
}
if (!window.cancelAnimationFrame) {
window.cancelAnimationFrame = function(id) {
clearTimeout(id);
};
}
应用
完整代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css"> * { padding: 0; margin: 0; } #e{ width :100px; height :100px; background-color :red; position : absolute; } </style>
</head>
<body>
<p id="e"></p>
</body>
<script type="text/javascript"> window.requestAnimFrame = (function() { return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function(callback) { window.setTimeout(callback, 1000 / 60); }; })(); var e = document.getElementById("e"); var flag = true; var left = 0; function render() { left == 0 ? flag = true : left == 100 ? flag = false : ''; flag ? e.style.left = ` ${left++}px` : e.style.left = ` ${left--}px`; } (function animloop() { render(); requestAnimFrame(animloop); })(); </script>
</html>
右边宽度固定,左边自适应
第一种:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css"> * { padding: 0; margin: 0; } body{ display :flex; } .left{ background-color:red; height : 200px; flex:1; } .right { background-color:cadetblue; height : 200px; width : 100px; } </style>
</head>
<body>
<div class="left"></div>
<div class="right"></div>
</body>
</html>
第二种:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css"> * { padding: 0; margin: 0; } div{ height : 200px; } .left{ float :right; width : 200px; background-color: chartreuse; } .right { margin-right:200px; background-color:salmon; } </style>
</head>
<body>
<div class="left"></div>
<div class="right"></div>
</body>
</html>
水平垂直居中
第一种:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css"> .center { width: 100px; height: 100px; position:absolute; background-color: red; top: 50%; left :50%; transform: translate(-50%,-50%); } </style>
</head>
<body>
<div class="center">
</div>
</body>
</html>
第二种:
将上方的transform: translate(-50%,-50%);换成
margin : -50px 0 0 -50px;
第三种:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css"> .center { width: 100px; height: 100px; position:absolute; background-color: red; margin :auto; top :0; bottom :0; left :0; right :0; } </style>
</head>
<body>
<div class="center">
</div>
</body>
</html>
第四种:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css"> body { display: flex; height: 600px; justify-content: center; align-items: center; border :1px solid red; } .center { width: 100px; height: 100px; background-color: red; } </style>
</head>
<body>
<div class="center">
</div>
</body>
</html>
四种定位的区别
- static是默认值
- relative相对定位,相对于自身原有位置进行偏移,仍然处于标准文档流之中
- absolute绝对定位,相对于最近的已定位的祖先元素(position不是static的元素),以最近的祖先元素为参考标准。如果无已定位祖先元素,以body元素为偏移参照基准,完全脱离了标准文档流
- flexd固定定位的元素会相对于视窗来定位,这意味着即便页面滚动,他还是会停留在相同的位置。一个固定定位元素不会保留它原本在页面应有的空隙
Flex布局用的多吗
因为项目考虑兼容IE9所以直接说用的不多
移动端适配怎么做的
使用媒体查询做的响应式布局,根据不同屏幕宽度加载不同的css
let和var的区别
let是ES6新添加声明变量的命令,它类似于var。但是有很大的不同:
- var声明的变量,其作用域为该语句所在的函数内,且存在变量提升的现象
- let声明的变量,其作用域为该语句所在的代码块内,不存在变量的提升
- let不允许重复声明
为什么var可以重复声明?
当我们执行代码的时候(如a=1)编译器和引擎还会进行两项额外的操作:判断变量是否已经声明:
- 首先编译器对代码进行分析拆解,从左到右遇见var a则编译器就会询问作用域是否已经存在a的变量了,如果不存在如果不存在就招呼作用域声明一个新的变量a若已经存在了就忽略var继续向下编译
- 引擎遇见a=1同样会询问当前作用域下是否由变量a存在就赋值,不存在就顺着作用域链向上查找,若最终找到了就赋值,没有就让作用域声明一个变量并且赋值
封装一个函数,参数是定时器的时间,.then执行回调函数
function sleep(time){
return new Promise((resolve)=>setTimeout(resolve,time)); }
一个关于this指向的问题
obj={
name:'a',
getName:function(){
console.log(this.name);
}
}
var fn=obj.getName;
obj.getName();
var fn2=obj.getName();
fn();
fn2();
CommonJS中的require/exports和ES6中的import/export区别?
- CommonJS模块的重要特性是加载时执行,及脚本代码在require的时候,就会全部执行。一旦出现某个模块被“循环加载”就只输出已经执行的部分,还没有执行的部分是不输出的。
- ES6模块是动态引用,如果使用import从一个模块加载变量,那些变量不会缓存,而是成为一个指向被加载模块的引用,需要开发者自己保证,真正取值的时候能够取到值
- impor/export最终都是编译为require/exports来执行的
- CommonJS规范规定,每个模块内部,module变量代表当前模块,这个变量是一个对象,他的exports属性是对外的接口,加载某个模块,其实是加载该模块的module.exports属性
- export命令规定的是对外的接口,必须与模块内部的变量建立一一对应的关系
一行代码实现数组去重
console.log(...new Set([6,6,5,5,1,2,3]));
使用addEventListener点击li弹出内容 ,并且动态添加li之后有效
<body>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
<button onclick="cccc()">添加</button>
<script type="text/javascript"> var a=5; var lis=document.querySelectorAll('li'); for(var i=0;i<lis.length;i++){ lis[i].addEventListener('click',function(e){ alert(e.target.nodeName); if(e.target&&e.target.nodeName.toUpperCase()=="LI"){ alert(e.target.innerHTML); } },false); } function cccc(){ var uls=document.querySelector('ul'); var l=document.createElement('li'); l.innerText=a++; l.onclick=function(){ alert(this.innerText); } uls.appendChild(l); } </script>
</body>
怎么判断两个对象相等
参考:
obj={
a:1,
b:2
}
obj2={
a:1,
b:2
}
obj3={
a:1,
b:2
}
console.log(JSON.stringify(obj)==JSON.stringify(obj2));
console.log(JSON.stringify(obj)==JSON.stringify(obj3));
项目做过哪些性能优化
- 减少HTTP请求数
- 减少DNS查询
- 使用CDN
- 避免重定向
- 图片懒加载
- 减少DOM元素数量
- 减少DOM操作
- 使用外部Javascript和CSS
- 压缩JavaScript,css字体,图片
- 优化CSS Script
- 使用iconfont
- 字体裁剪
- 多域名分发划分内容到不同的域名
- 尽量减少iframe使用
- 避免图片src为空
- 把脚本放在页面的底部
模块化开发是怎么做的?
使用命名空间
还没有评论,来说两句吧...