码迷,mamicode.com
首页 > Web开发 > 详细

JS常用面试题

时间:2017-07-22 16:53:33      阅读:243      评论:0      收藏:0      [点我收藏+]

标签:基础   aaa   inpu   bre   pen   css   click   调用   占用   



一、闭包:
 
1、函数嵌套函数、内部函数可以引用外部函数的参数和变量。
参数和变量不会被垃圾回收机制所收回
 
function aaa(a){
var b = 5;
function bbb(){
alert(a); //内部函数引用外部函数的参数
alert(b);//内部函数引用外部函数的变量
}
 
}
 
2、好处:
 
1)希望一个变量长期驻扎在内存当中。
2)避免全局变量的污染
3)私有成员的存在
 
 
function aaa(){
var a = 1; //局部,避免在函数外面是全局,影响其他变量
return function (){
a++;
alert(a);
}
 
}
var b = aaa();
b(); //2
b(); //3
 
```
function fn1() {
var a = 1;
 
function fn2() {
//我们是可以访问到fn1中定义a的值的
//alert(a);
alert(a++);
}
 
fn2();
}
 
fn1(); // 1
fn1();// 1 //当一个函数被执行的时候,和函数有关的一些变量会被申明(出现在内存中),当这个函数执行完成以后,如果函数中申明的变量没有再被其他地方所调用,则和这个函数有关的数据自动会被销毁
 
 
 
function fn1() {
var a = 1;
 
function fn2() {
alert(a++); // alert(a); a=a+1;
//alert(++a) // a=a+1; alert(a);
}
 
return fn2; //返回出去的是一个引用类型的值
}
 
var f = fn1();// f 和 fn2 指向的同一内存地址,所以fn1中的变量和函数不会被销毁
 
f(); // 1
f(); // 2
f = 1; // 断开,f 与 fn2 不指向同一内存,fn1销毁其中的变量和函数
f = fn1(); // f 重新和fn2建立关系
f(); // 1
 
 
3、用法:
 
1)代码模块化:
 
函数声明 转成 函数表达式:(代码模块化,减少全局变量的污染)
 
第一种用法:函数自执行:
 
(function (){
 
alert(1);
 
})();
 
第二种用法:return写法:
 
var aaa = (function(){
var a = 1;
return function(){
a++;
alert(a);
 
}
 
})();
 
aaa(); //2
aaa(); //3
 
私有成员的存在:
 
var aaa = (function(){
var a = 1;
function bbb(){
a++;
alert(a);
}
 
function ccc(){
a++;
alert(a);
}
 
return {
 
b:bbb,
c:ccc
 
}
 
})();
 
aaa.b(); //2
aaa.c(); //3
 
在外面调用不到a,bbb,ccc
 
 
2)在循环中直接找到对应元素的索引:
 
 
var li = document.getElementsByTagName(‘li‘);
 
for(var i = 0;i<li.length;i++){
 
li[i].onclick = function(){
alert(i); // 3,点击哪一个li都是3,当点击的时候for循环已经结束了为3
}
}
 
 
闭包写法
 
var li = document.getElementsByTagName(‘li‘);
 
for(var i = 0;i<li.length;i++){
 
(function(){
 
li[i].onclick = function(){
alert(i); // 点击第一个弹出1,第二个弹出2,第三个弹出3
}
 
})(i);// i 驻扎在内存中。
 
 
}
 
 
return写法
 
for(var i = 0;i<li.length;i++){
 
li[i].onclick = (function(){
return function(){
alert(i);
}
})(i);// i 驻扎在内存中。
}
 
````
模拟选项卡:
 
for (var i=0; i<aInput.length; i++) {
//show(i);
 
(function(i) { //这里面的包括形式参数在内的所有 i 都和外面的i无关,仅仅是个形参,可以换成任何字母
aInput[i].onclick = function() {
for (var j=0; j<aInput.length; j++) {
aInput[j].style.background = ‘‘;
aP[j].style.display = ‘none‘;
}
 
aInput[i].style.background = ‘yellow‘;
aP[i].style.display = ‘block‘;
}
})(i);//这个i代表for循环中的i
 
}
 
以上写法就相当于,定义一个带参函数show(a),然后调用,并传参:show(i);
 
4、IE下会引发内存泄漏,内存一直增加占用cpu。
 
事件中的函数中引用外部对象时:
 
window.onload = function(){
 
var div = document.getElementById(‘div‘);
 
div.onclick = function(){
 
alert(div.id); // div 是onclock函数外部的div,引发内存泄漏
}
 
//解决方法1:
 
window.onunload = function(){
 
div.onclick = null;//内存释放
 
}
 
}
 
 
 
window.onload = function(){
 
var div = document.getElementById(‘div‘);
 
//解决方法2代码:
var id = div.id;
 
div.onclick = function(){
 
alert(id); // div 是o‘clock函数外部的div,引发内存泄漏
}
//解决方法2代码:
div = null;//让对象为空
 
}
 
 
 
二、函数声明与函数表达式:
 
 
函数声明: function 函数名(){}
 
函数表达式: var a = function 函数名(可写可不写)() { }
 
写函数名:命名函数表达式
不写: 匿名函数表达式
 
function aaa(){} //函数声明
 
前面有 =是表达式:
 
var a = function aaa(){} //命名函数表达式
 
var a = function () {} // 命名函数表达式
 
括号中的都是表达式:
 
(function aaa(){}) //表达式
 
位运算符都是表达式:
 
~function aaa(){}
+function aaa(){}
-function aaa(){}
 
 
区别:
 
1.函数表达式可以直接后面加括号执行。而函数声明是不可以的。
2.函数声明可以被提前解析出来的。js的预解析。
 
错误:function aaa(){}();
 
正确:var a = function aaa(){}(); //直接执行
 
~function aaa(){}();
 
(function aaa(){})();
 
 
兼容性:
 
函数表达式写法不要在外部调用函数名
 
var a = function aaa(){
alert(2);
}
 
a(); 所有浏览器都兼容
 
//aaa();//外面找不到,不推荐使用
 
 
 
 
函数表达式:
 
alert(fn1); //undefined
 
//申明一个变量fn1,赋值了一个函数
 
var fn1 = function() {
alert(1);
}
 
函数声明:
 
alert(fn2); //function
 
function fn2() {
alert(2);
}
 
 
 
三、对象和函数都是引用的关系
 

var a = 5;
var b = a;
b += 3;
alert(b);//8
alert(a);//5
 
 
对象引用:
 
var a = [1,2,3];
var b = a;//a把内存地址也给了b,a和b共用一个地址
b.push(4);
alert(b);//1,2,3,4
alert(a);//1,2,3,4
 
 
 
 
var a = [1,2,3];
var b = a;//a把内存地址也给了b,a和b共用一个地址
b = [1,2,3,4];//b在内存当中又重新占了一个地址,与a分离,与之前的b不同,修改b也不会影响到a了。
 
alert(b);//1,2,3,4
alert(a);//1,2,3
 
 
 
var obj = {
a:10
 
};
 
var obj2 = obj;
obj2.a = 20;
alert(obj.a);//20

 
四、事件委托
 
事件委托(事件代理):利用冒泡原理
 
event对象的事件源:不管在哪个事件中,只要你操作的那个元素就是事件源
 
ie:window.event.srcElement
 
标准下:event.target
 
nodeName:找到当前元素的标签名
 
好处:
 
1)提高性能
 
 
例子:移到li使标签变颜色。移出颜色消失。移到ul身上没反应。
 
window.onload = function(){
 
var oUl = document.getElementById(‘ul‘);
var oLi = oUl.getElementsTageName(‘li‘);
 
/*for(var i = 0; i < oLi.length;i++){
oLi[i].onclick = function (){
alert(123);
}
}*/
 
//事件委托:
oUl.onmouseover = function(ev){
 
var ev = ev || window.event;
 
var target = ev.target || ev.srcElement;
 
if(target.nodeName.toLowerCase()==‘li‘){
 
target.style.background = ‘red‘;
 
}
}
oUl.onmouseout = function(ev){
 
var ev = ev || window.event;
 
var target = ev.target || ev.srcElement;
 
target.style.background = ‘ ‘;
 
}
}
 
 
2)新添加的元素还会有之前的事件
 
 
window.onload = function(){
 
var oUl = document.getElementById(‘ul‘);
var oLi = oUl.getElementsTageName(‘li‘);
var iNow = 4;
 
oUl.onmouseover = function(ev){
 
var ev = ev || window.event;
 
var target = ev.target || ev.srcElement;
 
if(target.nodeName.toLowerCase()==‘li‘){
 
target.style.background = ‘red‘;
 
}
 
}
oUl.onmouseout = function(ev){
 
var ev = ev || window.event;
 
var target = ev.target || ev.srcElement;
 
target.style.background = ‘ ‘;
 
}
 
//点击一次按钮后会在ul中新添加一个li,当不使用事件委托,直接在li上添加鼠标 移入移出事件,那么新添加的li元素就不会 存在之前li的鼠标移入移出事件。如果使 用事件委托,之前的li事件效果也会添加到新添加的li元素身上,原理就是利用了冒 泡。
button.onclick = function(){
 
iNow++;
var oLi = document.createElement(‘li‘);
oLi.innerHTML = 1111* iNow;
oUl.appendChild(oLi);
 
}
}
 
 
 
 
 
五:排序:
 
 
快速排序:
 
 
1、找一个处于中间位置的基准点
2、建立两个数组,分别存储左边和右边的数组。比基准小的放前面,比基准大的放后面。
3、利用递归进行下次比较
 
递归:一个函数进入下一个这个函数又进入,遇到条件返回上一个,一层一层返回到第一个。
 
1)函数调用函数自身,执行递的动作
2)最后一次判断一个终止条件,可以执行归的动作。
 
 
递归求阶乘:
 
function test(n){
 
if(n==1){//当到1时,结束递的过程,开始倒着进行归过程
return 1;//一层层返回,最后一次返回到上一次的函数...
}
 
return n*test(n-1);// 4x3x2
}
alert(test(4));
 
 
快排:
 
function quickSort(arr){
 
if(arr.length<=1){ //数组为空或者有一个数
 
return arr;
 
}
var num = Math.floor(arr.length/2);//获取中间位置的索引
 
var numValue = arr.splice(num,1);//把中间位置的基准点分离出来
 
var left = [];
 
var right = [];
 
for(var i =0;i<arr.length;i++){
 
if(arr[i]<numValue){//如果小于基准点,放在left[]中
 
left.push(arr[i]);
 
}else{
 
right.push(arr[i]);
 
}
 
}
 
//递归第二次是根据第一次基准点分成的左右,分别在左边和右边各找个中间的基准点,再次划分left和right...
return quickSort(left).concat([numValue],quickSort(right));//合并,递归
 
}
 
alert(quickSort([12,5,37,6,22,40]);)//5,6,12,22,37,40
 
 
 
冒泡排序:
 
 
for (var i=0; i<arr.length-1; i++) {
 
var f = false;
 
for (var j=0; j<arr.length-1-i; j++) {
var a = arr[j];
var b = arr[j+1];
 
if (a < b) {
f = true;
arr[j] = b;
arr[j+1] = a;
}
}
 
if (!f) {
break;
}
 
alert(arr);
 
}
 
 
六、枚举算法
 
枚举算法:
 
从众多的候选答案中用for来做筛选,通过if找出正确的解
 
 
七、JS的跨域:
 
同一个域名下的js文件不存在跨域问题
 
ajax不能跨域
 
解决跨域问题:
 
1)子域和主域都设置document.domain = ‘a.com‘;
 
2)服务器代理:XMLHttpRequest代理文件
 
3)script标签:jsonp的形式(单域操作)
 
jsonp: json + padding(内填充)
 
在a网站:在a网站调用b网站
<script>
function box(json){
 
alert(son.name); //leo
 
}
</script>
//jsonp在调用函数js的下面调用:
<script src="jsonp.js"></script>
 
 
在b网站:jsonp.js:
<script>
box({name = ‘leo‘});
</script>
 
 
4)location.hash
 
5)window.name
 
6)flash
 
7)html5 postMessage
 
 
 
 
 
 
 
八、iframe:
 
1)在主页面操作iframe页面中元素方法:
 
var oIframe = .....
 
所有浏览器都支持:
 
oIframe.contentWindow.document.getElementById(‘div‘)...
 
或者:
 
ie 6 7不支持:
 
oIframe.contentDocument.getElementById(‘div‘)...
 
 
2)在iframe页面中操作父级页面元素方法:
 
window.parent.document.getElementById(‘div‘)...//父层页面
 
window.top.document.getElementById(‘div‘)...//最顶层页面
 
 
 
ie下iframe的unload事件只能用绑定的形式
 
 
 
九、console:
 
 
console.log()
 
console.warn();//警告提示
 
console.error();//错误提示
 
console.group()//分组开始
 
console.groupEnd();//分组结束
 
分组开始和结束之间一般添加console.log()进行调试
 
console.dir();输出对象所有信息
 
console.dirxml();显示当前元素包含的代码结构
 
console.assert();如果是假的断言失败,如果是真的断言不提示信息
 
console.trace();当前函数的执行过程
 
console.time(‘计时器‘);代码执行时间。括号中写个标题,表示开始。
 
...代码
 
console.timeEnd(‘计时器‘);表示时间结束。括号中写的内容与开始时一样
 
console.profile();测试代码性能,括号中可以为空。
 
...代码
 
console.profileEnd();
 
 
 
 
 
 
十、DOM 优化:
 
1、dom与JavaScript:
 
尽量减少js操作dom 的次数
 
innerHTML与dom方法:
 
如果要创建多个元素li,在for循环前面声明一个变量:var str =" "; 然后在for循环里用str += ‘<li></li>‘;后在for循环后,添加到ul.innerHTML = str;
 
var ul = document.get ...
 
var str = " ";
 
for(var i =0;i<3000;i++){
 
str += ‘<li></li>‘;
 
}
 
ul.innerHTML = str;
 
 
2、减少dom操作
 
1)节点克隆 - cloneNode
 
var ul = doc...
var li = document.createElement(‘li‘);
ul.innerHTML = ‘li‘;
for(var i = 0;i<3000;i++){
 
var new = li.cloneNode(true);
ul.appendChild(new);
 
}
 
 
2)访问元素集合 - 尽量用局部变量
 
var lei = li.length;//优化
 
for(var i = 0;i<len;i++){
 
li[i]....
}
 
 
3)元素节点 - 尽量用只获取元素的节点方法
 
childNodes:能获取元素节点、文本节点
children:只能获取元素节点,推荐使用
 
firstChild:能获取元素节点、文本节点
firstElementChild:只能获取元素节点,推荐使用
 
 
4)选择器API
 
querySelector、querySelectorAll
 
 
 
3、dom与浏览器:
 
 
重排:改变页面的内容(改变元素的宽高和位置)
重绘:浏览器显示内容(重排后的显示就是重绘)
 
改变元素的背景颜色是重绘
 
1)添加顺序 - 尽量在appendChild前添加操作
 
2)合并dom操作 - 利用cssText
 
3)缓存布局信息 - 把操作用变量先保存起来
 
4)文档碎片 - createDocumentFragment();创建少的话提高不大
 
var ul = document.get...
 
var frag = document.createDocumentFragment();
 
for(var i = 0 ; i <3000; i++){
 
var li = document.createElement(‘li‘);
 
frag.appendChild(li);
 
}
 
ul.appendChild(frag);
 
 
4、dom与事件的关系:
 
可以用事件委托
 
5、dom与前端模板:
 
能更好地对逻辑和视图分离,MVC架构的基础
 
 
 
 
十一、变量预解析
 
 
 
alert(a);
//在很多的其他语言中,变量需要先申明再使用,但是在js中我们可以先使用再申明(虽然这里的结果不是10,是undefined)
var a = 10;
//在js中,js解析器会对我们的代码做一些初始化分析的工作,其他包含了这么一项内容,解析器会把程序中变量的申明在程序代码执行之前做一个初始化, 解析器会把变量的申明提前处理,上面的先调用,后申明其实也可以是下面这样
 
变量预解析:
 
var a; //申明会提前,赋值不会提前
 
alert(a);
 
a = 10;//赋值
 
作用域:
 
var a = 10;
 
function fn() { //函数申明
//var a;
alert(a); //函数内部的a
var a = 100; //申明被提前到了当前作用域的最开始
alert(a);
}
 
fn(); //undefined 100
 
 
 
 
十二、callee 和 caller
 
 
callee 返回正在执行的函数本身的引用,它是arguments的一个属性
 
1 这个属性只有在函数执行时才有效
2 它有一个length属性,可以用来获得形参的个数,因此可以用来比较形参和实参个数是否一致,即比较arguments.length是否等于arguments. callee.length
3 它可以用来递归匿名函数。
 
function fn() {
//arguments.callee => 当前函数
alert(arguments.callee);// function fn(){}
}
 
eg:让setTimeout来模拟setInterval
 
函数递归方法:
 
var a = 1;
 
function interval() {
setTimeout(function() {
document.title = a++;
interval();
}, 100);
}
 
interval();
 
利用闭包自执行和callee来递归:
 
var a = 1;
 
(function() {
var _arguments = arguments;
setTimeout(function() {
document.title = a++;
_arguments.callee(); //_arguments代表之前定义的父级函数的
}, 100);
})();
 
 
 
caller:返回一个函数的引用,这个函数调用了当前的函数。即调用该函数的函数。
 
使用这个属性要注意:
 
1 这个属性只有当函数在执行时才有用
2 如果在javascript程序中,函数是由顶层调用的,则返回null
functionName.caller: functionName是当前正在执行的函数。
 
function fn1() {
console.log(1);
console.log(fn1.caller);//fn2
}
 
function fn2() {
console.log(2);
console.log(fn2.caller); //null
fn1();
}
 
fn2(); //2 -> null -> 1 -> fn2
 
 
 
十三、call 和 apply
 
 
call和apply都是能改变函数内部this的指向
 
function fn1(a, b) {
console.log(this);
console.log(a + b);
}
 
fn1.call(document, 1, 2);// 第一个参数是this的指向,可以为null,其后的都是该函数的参数
 
apply 和call基本一致,不同的是参数的传递上
 
fn1.apply(document, [1, 2]); //第二个参数就是fn1中的arguments
 
求最大值:
 
var arr = [1,6,4,8,3,10,2];
 
//console.log( Math.max(1,6,4,8,3,10,2) ); //arguments => [1,6,4,8,3,10,2]
 
console.log( Math.max.apply(null, arr) ); //arguments => arr
 
 
十四、this
 
this
* 函数外 : window
* 函数内 :
* 当一个函数被对象调用,则该函数内的this指向调用该函数的对象
* 当一个函数被事件调用,则该函数内的this指向触发该事件的对象
* 通过call、apply去调用一个函数,那么这个函数指向call、apply的第一个参数(如果call、apply的第一个参数是undefined/null,则this指向调用该函数的对象)
 
十五、优化
 
减少全局变量:作用域链
只加载可视区内容
减少dom操作:事件委托 、文档碎片
减少请求和质量:合并JS 、压缩JS
能使用正则尽量使用正则
 
 
 
十六、变量的作用域:
 
1、外层的变量,内层可以找到(全局);内层的变量,外层找不到(局部)。
 
var a = 10;
function aaa(){
 
alert(a);
 
}
 
function bbb(){
 
var a = 20;
aaa();
 
}
 
bbb(); // 10
 
 
2、当var 不加的时候,会自动生成全局的变量(不建议这样写。最好把所有要定义的变量加上var)。
 
function aaa(){
 
var a = b = 10; // 拆分为b = 10; var a = 10;
 
}
aaa();
alert(a); // undefined
alert(b); // 10;
 
3、变量的查找是在代码逐行解读下就近原则去寻找var定义的变量或者function的参数 ,当就近没找到就到父级去找。
 
var a = 0;
 
function aaa(){
 
alert(a); // undefined;代码逐行解读
var a = 20;
 
}
aaa();
 
```
var a = 10;
 
function aaa(){
 
a = 20;
alert(a); //20
 
}
aaa();
 
```
 
var a = 0;
 
function aaa(){
 
alert(a); //10
a = 20;
 
}
aaa();
 
```
 
var a = 10;
function aaa(){
 
bbb();
alert(a);//10
function bbb(){
var a = 20;
}
 
 
}
 
 
4、当参数和局部变量重名的时候,优先级是等同的。
 
var a = 10;
 
function aaa(a){
 
alert(a); //10
var a = 20;
 
}
aaa(a);
 
 
5、基本类型的赋值,只是值的改变;对象之间是引用的关系,在内存中地址是相同的。
 
var a = 20;
 
function aaa(a){
 
a+=3;
 
}
aaa(a);
alert(a);//10 函数中的a和外部的a不同
 
 
···
 
var a = [1,2,3];
 
function aaa(a){
 
a.push(4); // 修改了外部a
 
}
aaa(a);
alert(a); // 1,2,3,4
 
···
 
var a = [1,2,3];
 
function aaa(a){
 
a = [1,2,3,4]; //在内存中重新生成了一个a,与外部的a不同
 
}
aaa(a);
alert(a); // 1,2,3

 

JS常用面试题

标签:基础   aaa   inpu   bre   pen   css   click   调用   占用   

原文地址:http://www.cnblogs.com/hello-web/p/7221472.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!