几道前端面试题
简答题:
1.事件绑定的几种方式?几种方式的区别以及优缺点?(原生js)
(1)、html元素里直接写,例如:<div onclick="javascript:alert("click")" ></div>
不推荐这么绑定。
(2)、W3C 推荐的js绑定。如:
document.getElementById('test').addEventListener('click',function(){
alert('click')
})
该方法同时支持事件处理的捕获和冒泡阶段。事件阶段取决于addEventListener最后的参数设置:false (冒泡) 或 true (捕获)。
在事件处理函数内部,this关键字引用当前元素。
事件对象总是可以通过处理函数的第一个参数(e)捕获。
可以为同一个元素绑定你所希望的多个事件,同时并不会覆盖先前绑定的事件,但是IE不支持,需要用attachEvent代替。
(3)传统的on绑定。
document.getElementById('test').onClick= function(){
alert('click')
}
传统方法只会在事件冒泡中运行,而非捕获和冒泡
一个元素一次只能绑定一个事件处理函数。新绑定的事件处理函数会覆盖旧的事件处理函数
事件对象参数(e)仅非IE浏览器可用
2.什么是事件委托?
事件委托就是事件目标自身不处理事件,而是把处理任务委托给其父元素或者祖先元素,甚至根元素(document)。
事件委托是利用事件的冒泡原理来实现的,何为事件冒泡呢?就是事件从最深的节点开始,然后逐步向上传播事件,举个例子:页面上有这么一个节点树,div>ul>li>a;比如给最里面的a加一个click点击事件,那么这个事件就会一层一层的往外执行,执行顺序a>li>ul>div,有这样一个机制,那么我们给最外面的div加点击事件,那么里面的ul,li,a做点击事件的时候,都会冒泡到最外层的div上,所以都会触发,这就是事件委托,委托它们父级代为执行事件。
3.css动画如何做性能优化?
这一题,本人也不太会,哈哈。一搜索出现一堆都是抄袭的同一篇文章,还请有经验人士说一下大家共同学习。
4.什么是模块化开发?你用的哪种方式进行模块化开发
一个模块就是实现特定功能的文件,有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就加载什么模块。
AMD 模块将被异步加载,模块加载不影响后面语句的运行。所有依赖某些模块的语句均放置在回调函数中。requirejs遵循此规范。
CMD 在CMD中,一个模块就是一个文件,格式为:
区别:
1. 对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。不过 RequireJS 从 2.0 开始,也改成可以延迟执行(根据写法不同,处理方式不同)。CMD 推崇 as lazy as possible.
2. CMD 推崇依赖就近,AMD 推崇依赖前置。
5.什么是闭包?闭包的应用场景
见第6题的链接里,王福朋对这部分也有很好的讲解。
6.Function.prototype是什么?Object.prototype是什么?
对于这个问题:给大家一个非常好的链接,看了之后绝对对这类问题理解的很透彻
7.你知道哪几种跨域请求数据的方式?jsonp的原理是什么?
就是利用<script>标签没有跨域限制的“漏洞”(历史遗迹啊)来达到与第三方通讯的目的。当需要通讯时,本站脚本创建一个<script>元素,地址指向第三方的API网址,形如:
<script src="http://www.example.net/api?param1=1¶m2=2"></script>
并提供一个回调函数来接收数据(函数名可约定,或通过地址参数传递)。
第三方产生的响应为json数据的包装(故称之为jsonp,即json padding),形如:
callback({"name":"hax","gender":"Male"})
8.回调嵌套太多,你是怎么解决的?
这个问题就是nodejs里面会很容易出现的回调地狱的解决问题。问题的原因在于异步执行时,根据回调函数的结果进行下一步操作,这一步操作里又会有一个回调,说的有点乱,看栗子:
$.ajax(
{ url: url,
method: 'get',
success: function(res) {
$.ajax({
url: url,
method: 'get', data:res //这里利用了第一次请求的结果再次请求
success: function(res2) {
resolve(res2);
},
error: function(xhr, statusText) {
reject(statusText);
}
});
},
error: function(xhr, statusText) {
reject(statusText);
}
});
这才只有两个嵌套,更多层的话你会疯掉的!解决这个问题的先要去了解一下Promise ,目前处理此类问题的js库有:Bluebird,Async.js 等等吧
9.如何实现对象方法的链式调用?
主要是生成对象,对象的每个方法里执行完想用的操作后return this(对象本身);举个栗子:
一个只有一个name属性的类,提供修改name和重置name的方法,
//链式调用 function ChainTest(name){ this.name = name; this.originalName = name; } ChainTest.prototype.changeName = function(newName){ this.name = newName; return this; } ChainTest.prototype.reset = function(){ this.name = this.originalName; return this; } var chain = new ChainTest("zhangsan");//新建对象 console.log(chain.name )// zhangsan chain.changeName('lisi'); console.log(chain.name ) // lisi chain.changeName('wangwu').reset();//链式调用 console.log(chain.name ) // zhangsan
10.Number函数与parseInt函数有哪些区别?
答:
Number():可以用于任何数据类型转换成数值;
parseInt()、parseFloat():专门用于把字符串转换成数值;
转换规则具体可以参考:http://www.cnblogs.com/hyuq/p/4131200.html
编程题:
1.请将字符串“asjchbnwnkanhe”按照字典顺序排序
解题思路:1、将字符串分解成数组。2、将数组排序。3、合并成数组。
function sort(str){ var arr = str.split(""); arr = arr.sort(); var resStr = arr.join(""); return resStr ; }
2.NaN属于什么类型?请写一个判断函数,功能如下:只有输入NaN的时候为true,其余输入值全部为false
解题思路:typeof(NaN)看出NaN是一个number类型的数据。NaN和任何数包括NaN自身相比较都是false,所以不能直接根据if(NaN == NaN)进行判断,先判断是否为number类型,然后再看他是不是0,如果不是则为NaN
function myIsNaN(num){ if(typeof(num) == "number"){ if(!num && num != 0){ return true }else{ return false } }else{ return false } }
3.请写出程序输出结果:
var arr = [];
(function run(){
var i=0;
for(;i<5;i++){
arr.push(function(){
console.log(i);
return i;
});
}
})();
arr = []
arr[2]();//请写出输出
var arr1 = arr.map(function(i){return i()});
var result = arr1.reduce(function(a,b){return a+b;});
console.log(result);//请写出输出
解题思路:首先run是一个自执行的函数,函数的功能是向arr[0] ~ arr[4] 中个放置一个函数,每个函数都是
function(){
console.log(i);
return i;
}
这个i引用的是run函数里的i,所以存在了一个闭包的现象(实际上数组里的每个元素都是这个函数,由于这个函数没有被执行,所以每个数组里的i是不确定的,只有到执行的时候i是什么值,输出才是什么值),所以
arr[2] = function(){
console.log(i);
return i;
}
执行的时候i是run函数里的i这时的i已经是5了,所以:
arr[2]() 输出为5;
var arr1 = arr.map(function(i){
return i()
});
这一步首先arr.map的返回值是一个数组,根据之前的分析可得:
arr1 = [5,5,5,5,5];
接下来就是这个:
var result = arr1.reduce(function(a,b){return a+b;});
首先是这个数组reduce函数(貌似不太常见这个方法),这个方法的的理解:
reduce(callback, initialValue)会传入两个变量。回调函数(callback)和初始值(initialValue)。假设函数它有个传入参数,prev和next,index和array。prev和next你是必须要了解的。reduce(callback, initialValue)会传入两个变量。回调函数(callback)和初始值(initialValue)。假设函数它有个传入参数,prev和next,index和array。prev和next你是必须要了解的。如果不太理解的话请移步:
http://www.jb51.net/article/60502.htm 先学一下,基本上就是遍历一下数组,但是每次遍历的是数组紧挨着的两个元素。
理解了这个函数之后应该很容易得出结果:
result = 25;
4.一个楼梯一共n个台阶,每次可以走1个台阶或者走2个台阶,请编写代码,输入为n,输出为多少种不同的走法?
解题思路:这是一个算法题。(作为找前端的人来说,这道题实在浪费时间,而且不应该,重要的是发现规律,发现不了肯定解决不了了)
先运用一下高中的数学解题思维看一下规律:
N Ways
1 1 //n=1 时只能走一步,所以只有一种方法
2 2 //n =2 时,一次走一步和一次走两步两种方法
3 3 //一次走一步,先走一步再走两步,先走两步再走一步
4 5 //自己琢磨吧,这里写不下了
5 8 //规律可以看出来了f[n] = f[n-1] + f[n-2]
//这里肯定会有递归算法了 function getWays(n){ if(n == 1){ return 1 }else if(n == 2){ return 2 }else{ //递归调用 return getWays(n-1) = getWays(n-2) } }
6.结果输出什么?为什么?
var a={},
b={key:'b'},
c={key:'c'};
a[b]=123;
a[c]=456;
console.log(a[b]);
解题思路:
首先这题得知道,object的属性值是不是可以为object?当然是不可以的。
因为键名称只能是字符串,b/c单作建会调用toString得到的都是[object Object],a[b],a[c]都等价于a["[object Object]"],那不就是更新[object Object]这个键的值了,执行后查看下a对象的的属性值就会发现确实是这样。