前端面试知识点整理(二)

三、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 继承

 

2.借助原型链实现继承
 
//借助原型链实现继承
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);

 

posted @ 2019-03-10 10:46  言叶以上  阅读(437)  评论(0编辑  收藏  举报