前端面试知识点整理(二)
三、DOM事件
- DOM事件的级别
- DOM事件模型(捕获,冒泡)
- DOM事件流
- 描述DOM事件捕获的具体流程
- Event 对象的常见应用
- 自定义事件
DOM事件级别
事件流
浏览器在当前页面与目标交互的过程中,动作是怎么传递的如何相应。
捕获阶段 —— 目标阶段 —— 冒泡阶段
具体流程
捕获:window -> document -> html -> body -> ... -> 目标元素
冒泡反之
用JS 获取body: document.body
用JS获取html: document.documentElement
Event 对象
event.preventDefault() 阻止默认行为
event.stopPropagation() 阻止冒泡行为
event.stopImmediatePrppagation() 事件相应优先级。给目标注册两个事件,执行一个阻止另一个
event.currentTarget 区分当前哪个元素被点击
event.target 返回事件的目标节点
自定义事件
var eve = new Event('custome'); ev.addEventListener('custome', function(){ console.log('custome'); }); ev.dispatchEvent(eve);
<div id="ev"> <style> #ev{ width: 300px; height: 100px; background-color: red; color: #fff; text-align: center; line-height: 100px; } </style> 目标元素 </div> <script> var ev = document.getElementById('ev'); // 捕获事件流程 // 第三个参数为true时,事件句柄在捕获阶段执行 // 把true改为false,就是冒泡阶段流程 window.addEventListener('click',function(){ console.log('window capture'); },true); document.addEventListener('click',function(){ console.log('document capture'); },true) document.documentElement.addEventListener('click',function(){ console.log('html capture'); },true); document.body.addEventListener('click',function(){ console.log('body capture'); },true); ev.addEventListener('click',function(){ console.log('ev capture'); },true) </script>
Event 自定义事件
// 自定义事件 'test' var eve = new Event('test'); //注意,参数要和事件名一致 ev.addEventListener('test',function(){ console.log('test dispatch'); }) // 事件派发,直接触发了 ev 上的事件 //ev.dispatchEvent(eve); setTimeout(function(){ ev.dispatchEvent(eve); }, 2000);
CustomEvent 自定义事件
//创建自定义事件对象,并传入数据 const ev = new CustomEvent('msg',{ detail:{ title: 'this is custom event', id :'0010' } }) //创建该事件行为 document.body.addEventListener('msg',function(args){ console.log(args.detail) }) //最后绑定新事件对象 document.body.dispatchEvent(ev);
四、HTTP协议类
- HTTP协议主要特点
- HTTP报文的组成部分
- HTTP方法
- POST GET 区别
- HTTP状态码
- 持久连接
- 管线化
主要特点:
简单快速:每个资源是固定的,在协议中处理很简单的,只要输入URI
灵活:通过一个HTTP协议就可以完成不同数据类型的传输。
无连接:连接一次就断开不会保持连接
无状态:客户端再次请求,服务端是无法区分和上一次是否为同一身份
HTTP报文:
HTTP方法
GET - 获取资源
POST - 传输资源
PUT - 更新资源
DELETE - 删除资源
HEAD - 获得报文首部
HTTP 状态码
持久连接 keep-alive
HTTP 支持持久连接 (1.1版本)
HTTP协议采用请求-应答模式,每个请求/应答客户和服务器都要新建一个连接,完成后立即断开。
使用Keep-alive模式时,keep-alive功能避免了建立或者重新连接。
管线化
类似于将请求和响应打包起来
五、原型链
- 创建对象有几种方法
- 原型、构造函数、实例、原型链
- instanceof 的原理
- new 运算符
创建对象
//1 var o1 = {name:'o1'} var o2 = new Object({name: 'o2'}) //2 var M = function(name){this.name = name} var o3 = new M('o3') //3 var p = {name:'p'} var o4 = Object.create(p)
实例:上例中的o1, o11, o2, 只要是对象,它就是一个实例。
构造函数 : new 后面操作的函数就是构造函数。
构造函数是可以使用 new 运算符来生成一个实例,构造函数也是函数,函数都有一个prototype属性,prototype会初始化一个空对象,就是原型对象。原型对象都有一个构造器,构造器指向声明的那个构造函数。
构造函数 与 原型对象的关系:
实例 与 原型对象 的关系:
原型链:
从一个实例对象往上找构造 这个实例相关联的对象,再往上找又有创造它的上一级原型对象,以此类推一直到Object.prototype 原型对象终止。
M.prototype.say = function(){ console.log('say hi') } var o5 = new M('o5')
就是说,通过原型链找到原型上的方法,这个方法是被实例所共有的。
在访问一个实例的时候,在这个实例本身没有找到方法属性,它一直往原型对象上找(通过 __proto__ )。
函数才有 prototype,实例对象才有 __proto__ ,而函数(也是一个对象)的 __proto__ 就是Function构造函数的实例。
instanceof
instanceof 可以在继承关系中用来判断一个实例是否属于它的父类型
constructor 是用来判断实例是属于哪个原型的
六、面向对象
- 类的声明
- 生成实例
- 如何实现继承
- 继承的几种方式
//类的声明 function Animal() { this.name = 'name'; } //es6中的class声明 class Animal2{ constructor(){ this.name = name; } } //实例类的对象 console.log(new Animal(), new Animal2());
1.借助构造函数实现继承
//借助构造函数实现继承 function Parent1() { this.name = "parent1"; } function Child1() { //apply call 改变函数运行上下文,把父函数的this挂载到子函数内, 实现子函数继承 Parent1.call(this); this.type = "child1"; } console.log(new Child1()); /* Child1 name: "parent1" type: "child1" */
缺点:Parent1 原型链上的东西并没有被 Child1 继承
//借助原型链实现继承 function Parent2() { this.name = "parent2"; } function Child2() { this.type = "child2"; } //任何一个函数都有Prototype这个属性,作用就是让构造函数的实例能访问到它的原型对象上 Child2.prototype = new Parent2(); console.log(new Child2());
缺点:原型对象是共用的,改变一个另一个也会改变
function Parent2() { this.name = "parent2"; this.play = [1, 2, 3]; } function Child2() { this.type = "child2"; } //任何一个函数都有Prototype这个属性,作用就是让构造函数的实例能访问到它的原型对象上 Child2.prototype = new Parent2(); console.log(new Child2()); var s1 = new Child2(); var s2 = new Child2(); console.log(s1.play, s2.play); s1.play.push(4);
3.组合方式实现继承
function Parent3() { this.name = "parent3"; this.play = [1, 2, 3]; } function Child3() { Parent3.call(this); this.type = "child3"; } Child3.prototype = new Parent3(); var s3 = new Child3(); var s4 = new Child3(); s3.play.push(4); console.log(s3.play); console.log(s4.play);
缺点:Parent3() 执行了两次
优化方案1:
function Parent4() { this.name = "parent4"; this.play = [1, 2, 3]; } function Child4() { Parent4.call(this); this.type = "child4"; } // 继承父级的原型 Child4.prototype = Parent4.prototype; var s5 = new Child4(); var s6 = new Child4(); s5.play.push(4); console.log(s5.play); console.log(s6.play);
缺点:原型全指向了Parent4
优化方案2(完美写法):
function Parent5() { this.name = "parent5"; this.play = [1, 2, 3]; } function Child5() { Parent5.call(this); this.type = "child5"; } // 继承父级的原型 Child5.prototype = Object.create(Parent5.prototype); Child5.prototype.constructor = Child5; var s7 = new Child5(); console.log(s7 instanceof Child5, s7 instanceof Parent5); console.log(s7.constructor);