完美世界前端实习生一面面经和总结
完美世界前端一面面经
主要还是以基础的问题为主,涉及了很多js的基础知识。
1. js如何进行事件监听?
事件就是在什么时候做什么事,比如在鼠标移入的时候弹出窗口就叫一个事件,事件监听也就是事件绑定。
JavaScript事件一共有三种监听方法分别如下:
1.1 事件监听一夹杂在html标签内
<div id="box" onClick="alert('HELLO WORLD')"> <div id="box2" onClick="notice();"></div> <div id="box3" onClick="service('HELLO WORLD'');"></div> </div> function notice(){ alert(HELLO WORLD'");} function service(str){ alert(str);}
说明:以上把事件监听功能onClick写到div中的形式是最古老原始形式,所有主流浏览器都支持。
类似行内CSS样式一样,是有效的(注意大小敏感),但是缺点和写到行内的CSS样式一样。
优点:
1)兼容性好,基本上所有浏览器都支持该种方式
缺点:
1)复用性不好。
2)JS与HTML夹杂到一块,代码混乱,发生错误难以检测和排除,不利于分工合作。
3)如果发生修改需要同时修改HTML和JS,改动相对困难。
为了解决以上问题把事件监听形式改进如下,以下方式也是目前主流的使用方式之一。
1.2 事件监听方法二 on+“事件”
<div id="box"></div> var box = document.getElementById("box"); box.onclick = function(){ alert("HELLOW WORLD"); };
说明:通过以上形式可以把事件与HTML完全分离,是最常用的形式之一。
以上对于一般项目已经足够用。但如果想单击一次执行多个函数时,这种绑定方式就无法完成了
box.onclick = function(){ fnA(); fnB(); }; function fnA(){ alert("我会被执行"); } function fnB(){ alert("我也会被执行"); }
说明:这种情况下 alert(“HELLOW WORLD”) 就不会被执行了,也就是说后面的函数覆盖了之前声明的函数。
优点:
1)兼容性好,基本支持所有浏览器
2)做到了文档与JS的分离,方便后期的代码管理
缺点:
1)同一个事件,在执行多个函数时会发生覆盖
1.3 事件监听方法三 element.addEventListener(事件名,函数,冒泡/捕获)
<div id="box"> <div id="box1"></div> <div id="box2"></div> </div> var box = document.getElementById("box"); box.addEventListener("click",fnA,false); box.addEventListener("click",fnB,false); function fnA(){ alert("HELLO WORLD!"); } function fnB(){ alert("HI CHINA!"); }
上面两个函数fA(),fB()都会执行,不会发生覆盖现象。
使用介绍:
addEventListener是DOM2的标准语法,新版本主流浏览器基本都支持。但是老版本IE浏览器不支持;
这种绑定方法有三个参数:
第一个是事件类型,不需要on前缀,但事件名需加 " " ;
第二个参数是发生这个事件的时候要调用的函数;
第三个是布尔值的true或false.(默认值是false)
false代码是以冒泡型事件流进行处理,一般都选用false.
true意味着代码以捕获型事件流进行处理,不是必须不推荐使用。
优点:
1)做到JS与HTML文档分离,便于代码维护;
2)不会发生像on+"事件"的函数覆盖现象;
3)提供监听的事件以冒泡或者捕获的可选方式执行
缺点:
1)兼容性还不完善,老板IE浏览器可能不兼容;
2)方法名较长,记忆稍有难度
注:使用element.removeEventListener(type,listener,useCapture);方法可以移除已经添加的实际。
使用方法:box.removeEventListener(“click”,fnB,false);
参考文章:js事件监听
2. 事件冒泡和事件捕获的原理?
JS事件冒泡和事件捕获
事件冒泡和事件捕获是描述事件触发时序问题的术语。
事件捕获指的是从document到触发事件的那个节点,即自上而下由外到内的去触发事件。
相反的,事件冒泡是自下而上由内到外的去触发事件。
绑定事件方法(addEventListener)的第三个参数,就是控制事件触发顺序是否为事件捕获。true,事件捕获;false,事件冒泡。默认false,即事件冒泡。
Jquery的e.stopPropagation会阻止冒泡,意思就是到我为止,我的爹和祖宗的事件就不要触发了。
<div id="parent"> <div id="child" class="child"></div> </div>
document.getElementById("parent").addEventListener("click",function(e){ alert("parent事件被触发,"+this.id); }) document.getElementById("child").addEventListener("click",function(e){ alert("child事件被触发,"+this.id) })
点击child div输出结果:
child事件被触发,child
parent事件被触发,parent
结论:先child,然后parent。事件的触发顺序自内向外,这就是事件冒泡。
如果改变第三个参数的值为true:
document.getElementById("parent").addEventListener("click",function(e){ alert("parent事件被触发,"+e.target.id); },true) document.getElementById("child").addEventListener("click",function(e){ alert("child事件被触发,"+e.target.id) },true)
点击child div输出结果:
parent事件被触发,parent
child事件被触发,child
结论:先parent,然后child。事件触发顺序变更为自外向内,这就是事件捕获。
事件冒泡经典案例
<ul> <li>item1</li> <li>item2</li> <li>item3</li> <li>item4</li> <li>item5</li> <li>item6</li> </ul>
需求:鼠标放到li上对应的li的背景变为灰色
利用事件冒泡实现:
$("ul").on("mouseover",function(e){ $(e.target).css("background-color","#ddd").siblings().css("background-color","white"); })
也许有人会说,我们直接给所有li都绑上事件也可以啊,一点也不麻烦,只要……
$("li").on("mouseover",function(){ $(this).css("background-color","#ddd").siblings().css("background-color","white"); })
是,这样也行。而且从代码简洁程度上,两者是相若仿佛的。但是,前者少了一个遍历所有li节点的操作,所以在性能上肯定是更优的。
还有就是,如果我们在绑定事件完成后,页面又动态的加载了一些元素……
$("<li>item7</li>").appendTo("ul");
这时候,第二种方案,由于绑定事件的时候item7还不存在,所以为了效果,我们还要给它再绑定一次事件。而利用冒泡方案由于是给ul绑的事件所以不用再重新进行一次绑定了。
3. new 关键字来调用构造函数的时候发生了什么?
var obj = new Constructor();
第一,在内存中创建一个空对象obj。
第二,将这个空对象的__proto__成员指向了构造函数对象的prototype成员对象.
第三,执行构造函数,将构造函数的作用域赋给新对象。
第四,返回新对象obj。
4. this关键字的指向问题
- 普通函数中的this指向的是Window。
- 对象的方法中的this指向的是这个方法所属的对象。
- 构造函数中的this指向的是构造函数所创建的对象。
- 函数在定义的时候this是不确定的,只有在调用的时候才可以确定。
5. JS是如何实现继承的
既然要实现继承,那么首先我们得有一个父类,代码如下:
// 定义一个动物类 function Animal (name) { // 属性 this.name = name || 'Animal'; // 实例方法 this.sleep = function(){ console.log(this.name + '正在睡觉!'); } } // 原型方法 Animal.prototype.eat = function(food) { console.log(this.name + '正在吃:' + food); };
1. 原型链继承
核心: 将父类的实例作为子类的原型
function Cat(){ } Cat.prototype = new Animal(); Cat.prototype.name = 'cat'; // Test Code var cat = new Cat(); console.log(cat.name); console.log(cat.eat('fish')); console.log(cat.sleep()); console.log(cat instanceof Animal); //true console.log(cat instanceof Cat); //true
特点:
非常纯粹的继承关系,实例是子类的实例,也是父类的实例
父类新增原型方法/原型属性,子类都能访问到
简单,易于实现
缺点:
要想为子类新增属性和方法,必须要在new Animal()这样的语句之后执行,不能放到构造器中
无法实现多继承
来自原型对象的所有属性被所有实例共享(来自原型对象的引用属性是所有实例共享的)(详细请看附录代码: 示例1)
创建子类实例时,无法向父类构造函数传参
2. 构造继承
核心: 使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给子类(没用到原型)
function Cat(name){ Animal.call(this); this.name = name || 'Tom'; } // Test Code var cat = new Cat(); console.log(cat.name); console.log(cat.sleep()); console.log(cat instanceof Animal); // false console.log(cat instanceof Cat); // true
特点:
解决了1中,子类实例共享父类引用属性的问题
创建子类实例时,可以向父类传递参数
可以实现多继承(call多个父类对象)
缺点:
实例并不是父类的实例,只是子类的实例
只能继承父类的实例属性和方法,不能继承原型属性/方法
无法实现函数复用,每个子类都有父类实例函数的副本,影响性能
(写到一半,等待补充)
- 阿里巴巴2016前端开发实习生面试一面面经(总结)
- 阿里巴巴2016前端开发实习生面试一面面经(总结)
- 2018年蚂蚁金服前端一面总结(面向2019届学生)
- 4月1号腾讯实习生一面总结
- 前端实习生面试总结
- 唯品会web前端实习生一面二面经
- 2014腾讯实习生Android移动开发一面总结
- 网易2016实习生前端笔试题部分总结
- 2017实习生今日头条前端面经
- 蚂蚁金服2019实习生面经总结(已拿口头offer)
- 2015阿里巴巴前端实习生在线笔试考后总结
- 2019.04.15完美世界前端实习生笔试
- 腾讯2017暑期实习生OMG事业群一面面经
- [面经]汤森路透 软件开发暑期实习生 一面
- 【WEB】网易2017年前端工程师实习生招聘笔试编程题总结
- 百度质量部测试开发实习生面试总结(技术一面)
- 毕业一年左右的前端妹子面经总结
- 谈谈阿里实习生招聘面试经历及经验总结(回忆版)--前端开发
- 2018年蚂蚁金服前端一面总结(校招)