• JavaScript面试


    面试

    DOM事件类

    事件级别

    事件处理程序就是响应某个时间的函数,DOM事件分为3个级别:DOM 0级事件处理,DOM2级事件处理,DOM3级事件处理

    1. DOM0级事件

    el.onclick=function(){}

    var btn = document.getElementById('btn');
    btn.onclick = function(){
        alert(this.innerHTML);
    }
    

    当希望为同一个元素/标签绑定多个同类型事件的时候(如给上面这个btn元素绑定三个点击事件),是不被允许的。DOM0级事件绑定,给元素的事件行为绑定方法,这些方法都是在当前元素事件行为的冒泡阶段(或者目标阶段)执行的

    1. DOM 2级事件

    el.addEventlistener(event-name,callback,useCapture)

    event-name:事件名称,可以是标准的DOM事件

    callback:回调函数,当事件触发时,函数会被注入一个参数为当前的事件对象event

    userCapture:默认是false,代表事件句柄在冒泡阶段执行

    var btn = document.getElement('btn');
    btn.addEventListener("click",test,false);
    function test(e){
       e = e || window.event
        alert(e.target|| e.srcElement.innerHTML);
        btn.removeListener("click",test)
    }
    

    IE9以下的IE浏览器不支持addEventListener()和removeListener(),使用attachEven()与detachEvent()代替,因为IE9以下不支持事件捕获的,所以也没有第三个参数,第一个事件名称前要加on。

    1. DOM 3级事件
    • 在DOM2级事件的基础上添加了更多的事件类型。
    • UI事件,当用户与页面上的元素交互时触发,如:load、scroll
    • 焦点事件,当元素获得或失去焦点时触发,如:blur、focus
    • 鼠标事件,当用户通过鼠标在页面执行操作时触发如:dblclick、mouseup
    • 滚轮事件,当使用鼠标滚轮或类似设备时触发,如:mousewheel
    • 文本事件,当在文档中输入文本时触发,如:textInput
    • 键盘事件,当用户通过键盘在页面上执行操作时触发,如:keydown、keypress
    • 合成事件,当为IME(输入法编辑器)输入字符时触发,如:compositionstart
    • 变动事件,当底层DOM结构发生变化时触发,如:DOMsubtreeModified
    • 同时DOM3级事件也允许使用者自定义一些事件。

    DOM事件模型和事件流

    DOM事件模型分为捕获和冒泡。一个事件发生后,会在子元素和父元素之间传播。这种传播分为三个阶段。

    1. 捕获阶段:事件从window对象自上而下向目标节点传播的阶段
    2. 目标阶段:真正的目标节点正在处理事件的阶段;
    3. 冒泡阶段:事件从目标节点自下而上向window对象传播的阶段

    描述DOM事件捕获的具体流程

    捕获是从上到下,事件先从window对象,然后再到document(对象),然后是html标签(通过document.documentElement获取html标签),然后是body标签(通过document.body获取body标签),然后按照普通的html结构一层一层往下传,最后到达目标元素

    而事件冒泡的流程刚好是事件捕获的逆过程。

    事件代理(事件委托)

    由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理子元素的事件。这种方法叫做事件对的代理

    1. 优点
    • 减少内存消耗,提高性能
      假设有一个列表,列表之中有大量的列表项,我们需要在点击每个列表项的时候响应一个事件
      如果给每个列表项一一都绑定一个函数,那对于内存消耗是非常大的,效率上需要消耗很多性能。借助事件代理,我们只需要给父容器ul绑定方法即可,这样不管点击的是哪一个后代元素,都会根据冒泡传播的传递机制,把容器的click行为触发,然后把对应的方法执行,根据事件源,我们可以知道点击的是谁,从而完成不同的事。
    • 动态绑定事件
      在很多时候,我们需要通过用户操作动态的增删列表项元素,如果一开始给每个子元素绑定事件,那么在列表发生变化时,就需要重新给新增的元素绑定事件,给即将删去的元素解绑事件,如果用事件代理就会省去很多这样麻烦。
    1. 如何实现

      //给父层元素绑定事件
      document.getElementId('list').addEventListener('click',function(e){
          //兼容性处理
          var event =e||window.event
          var target =event.target ||event.srcElemnt;
          //判断是否匹配目标元素
          if(target.nodeName.toLocaleLowerCase === 'li'){
              console.log('this content is:',target.innerHTML)
          }
      })
      

      Event对象常见的应用

    • event.preventDefault()

      如果调用这个方法,默认事件行为将不再触发。什么是默认事件呢?例如表单一点击提交按钮(suvmit)跳转页面,a标签默认页面跳转或是锚点定位等。

      <a id="test" href="http://www.cnblogs.com">链接</a>
      <script>
          var test=document.getElementById('test');
          test.onclick =function(e){
              e =e ||window.event;
              e.preventDefault();
          }
      </script>
      

      实现输入框最多只能输入六个字符

      <input type="text" id="tempInp">
      <script>
         var tempInp = document.getElementById('tempInp')
         tempInp.onkeydown  =function(ev){
             ev=ev||window.event;
             let val =this.value.trim();//trim去除字符串首位空格
             let len =val.length
             if(len>=6){
                 this.value =val.substr(0,6);
                 //阻止默认行为去除特殊按键
                 let code =ev.which ||ev.keyCode;
                 if(!/^(46|8|37|38|39|40)$/.test(code)){
                     ev.preventDefault();
                 }
             }
         }
      </script>
      
    • event.stopPropagation()& stop.stopImmediatePropagation()

      event.stopPropagation()方法阻止事件冒泡到父元素,阻止任何父事件处理程序被执行。

    stop.stopImmediatePropagation()既能阻止事件向父元素冒泡,也能阻止元素同事件类型的其他监听器被触发。而stopPropagtion只能实现前者的效果。

    <button id="btn">click me</button>
    <script>
      var btn =document.querySelector('#btn');
      btn.addEventListener('click',function(event){
          console.log('btn click 1');
          event.stopImmediatePropagation();
      });
      btn.addEventListener('click',function(){
          console.log('btn click 2')
      })
      document.body.addEventListener('click',function(){
          console.log('body click')
      })
      //btn click 1  
    </script>	
    

    使用stop.stopImmediatePropagation()后。点击按钮时,不仅仅body绑定事件不会触发,与此同按钮的另一个点击事件也不会触发。

    • event.target & event,currentTarget

    event.target指向引起触发事件的元素,而event.currenttTarget则是事件绑定的元素,也就是说event.currentTarget始终是监听事件者,而event.target是事件的真正发出者

    <div id="a">
        <div id="b">
            <div id="c">
                <div id="d">
                </div>	
            </div>	
        </div>
    </div>
    <script>
      document.getElementId('a').addEventListener('click',function(e){
          console.log('target:’+e.target.id+'&currentTarget:'+e.currentTarget.id)
      })
        document.getElementId('b').addEventListener('click',function(e){
          console.log('target:’+e.target.id+'&currentTarget:'+e.currentTarget.id)
      })
        document.getElementId('c').addEventListener('click',function(e){
          console.log('target:’+e.target.id+'&currentTarget:'+e.currentTarget.id)
      })
        document.getElementId('d').addEventListener('click',function(e){
          console.log('target:’+e.target.id+'&currentTarget:'+e.currentTarget.id)
      })
    </script>	
    

    img

    当点击最里层的元素d的时候会依次输出

    target:d&currentTarget:d
    target:d&currentTarget:c
    target:d&currentTarget:b
    target:d&currentTarget:a
    
    • 自定义事件
    var eve =new event('custome');
    ev.addEventListener('custome',function(){
        console.log('custome')
    })
    ev.dispatchEvent(eve);
    

    原型链

    创建对象的方法

    直接字面量创建

    var objA ={};
    objA.name ='a';
    objA.sayname =function(){
        console.log('my name is'+this.name);
    }
    objA.sayName();
    console.log(objA.__proto__ === Object.prototype);//true
    console.log(objA instanceof Object) //true
    

    构造函数创建

    var B = function(name){
        this.name =name;
        this.sayname = function(){
            console.log('my name is'+this.name)
        }
    }
    var objB =new B('b');
    

    Object.Create()

    Object.create()方法创建一个新对象,使用现有的对象来提供新创建对象的__proro__

    const person = {
        isHuman:false,
        printIntroduction:function(){
            console.log(`my name is ${this.name}. Am I human ${this.isHuman}`);
        }
    };
    const me = Object.create(person);
    me.name = "Matthew";
    me.isHuman =true;
    me.printIntroduction();
    

    Object.create(proto,[propertiesObject])

    • proto必填参数,是新对象的原型对象,如上面代码里新对象me__proto__指向person。注意,如果这个参数是null,那新对象就彻彻底底是个空对象,没有继承Object.prototype上的任何方法和属性,如hasOwnProperty(),toString()
    var a = Object.create(null);
    console.log(a);
    console.log(a.__proto__);
    console.log(a.__proto__ === Object.prototype);//false
    console.log(a instanceof Object);false
    
    • propertiesObject是可选参数,指定要添加到新对象上的可枚举的属性(即其自定义的属性和方法,可用hasOwnProperty()获取的,而不是原型对象上的)的描述符及相应的属性名称。
    var bb = Object.create(null,{
        a:{
            value:2,
            writable:true,
            configurable:true
        }
    });
    console.log(bb);
    console.log(bb.__proto__);
    console.log(bb.__proto__===Object.prototype);
    console.log(bb instanceof Object);
    //-----------------------------------------------------------------------
    var cc =Object.create({b:1},{
        a:{
            value:3,
            writable:true,
            configurable:true
        }
    });
    console.log(cc);
    console.log(cc.hasOwnProperty('a'),cc.hasOwnProperty('b'));
    console.log(cc.__proto__);
    console.log(cc.__proto__ === Object.prototype);
    console.log(cc instanceof Object)
    

    Object.create()创建的对象原型指向传入的对象。跟字面量和new关键字创建有区别

    自己实现一个Object.create()

    Object.mycreate = function(proto,properties){
        function F(){};
        F.prototype = proto;
        if(properties){
            Object.defineProperties(F,properties);
        }
        return new F();
    }
    var hh = Object.myCreate({a:11},{mm:{value:10}})
    console.log(hh);
    

    总结

    • 字面量和new关键字创建的对象是Object的实例,原型指向Object.prototype,继承内置对象Object
    • Object.create(arg,pro)创建的对象的原型取决于argargnull,新对象是空对象,没有原型,不继承任何对象;arg为指定对象,新对象的原型指向对象,继承指定对象

    原型链

    instanceof原理

    1. instanceof的作用是用来做检测类型:
    • instanceof可以检测某个对象是不是另一个对象的实例:

      var Person = function(){}
      var student =new Person();
      console.log(student instanceof Person);//true
      
    • instanceof可以检测父类型

    function Person(){};
    function Student(){};
    var p =new Person();
    Student.prototype = p; //继承原型
    var s =new Student();
    console.log(s instanceof Student);//true
    console.log(s instanceof Person); //true
    
    1. instanceof检测一个对象A是不是另一个对象B的实例的原理:

    查看对象B的原型指向是否在对象A的原型链上。如果在,则返回true,如果不在返回false

    实例对象属性查找属性顺序是:实例对象内部---->构造函数原型链----->实例对象父对象的原型链

    new运算符

    var obj ={};
    obj.__proto__ = F.prototype;
    F.call(obj);
    

    执行new操作符,构造函数会经历以下三个步骤:

    1. 创建一个空对象,并且this变量引用该对象,同时还继承了该函数的原型
    2. 属性和方法被加入到this引用的对象中
    3. 新创建的对象由this所引用,并且最后隐式的返回this

    面向对象

    类的申明

    //在ES5中没有类的概念,开发者通过原型的方法,实现了类似于类的结构
    function Person(name){
        this.name =name;
    }
    Person.prototype.sayName =function(){
        console.log(`my name is ${this.name}`)
    }
    var p = new Person('haha');
    console.log(p.sayName)//haha
    
    //ES6中提供了class方法,实现类
    class Person(name){
        constructor(name){
            this.name =name;
        }
        //定义一个方法并且赋值给构造函数的原型
        sayName(){
            return this.name
        }
    }
    let p =new Person('haha');
    console.log(sayName);
    

    类的继承

    1. 借助构造函数继承
    function Parent1(){
        this.name ='Parent1'
    }
    Parent1.prototype.say = function(){
        console.log('hello')
    }
    function Child1(){
        Parent1.call(this)
        this.type ='child1'
    }
    console.log(new Child1());
    

    缺点:借助构造函数继承,不能继承父类的prototype原型上的方法

    1. 借助原型链实现继承
    function Parent2(){
        this.name ='Parent2'
    }
    Parent2.prototype.say =function(){
        console.log('h1')
    }
    function Child2(){
        this.type ='child2'
    }
    Child2.prototype =new Parent2();
    console.log(new Child2());
    c1 =new Child2();
    c2 =new Child2();
    

    缺点:因为原型链中的对象都是公用的,导致子类改变继承父类中的属性和方法,父类下的所有子类继承的属性和方法都会改变

    1. 组合继承
    function Parent3(){
        this.name ='parent3';
        this.play =[1,2,3]
    }
    function Child3(){
        Parent3.call(this);
        this.type ='child3'
    }
    Child3.prototype =new Parent3();
    var c3 =new Child3();
    var c4 =new Child4();
    c3.play.push(4);
    console.log(c3.play,c4.play)
    

    缺点:父类创建执行了两次,浪费了内存空间,子类的prototype指向不再是子类自己,而是指向父类

    function Parent5(){
        this.name ='parent5';
        this.play =[1,2,3]
    }
    function Child5(){
        Parent3.call(this);
        this.type ='child5'
    }
    Child5.prototype =Object.create(parent.prototype)
    Child5.prototype.constructor = Child5
    

    ES6继承

    //ES6
    class Parent{
        constructor(name){
            this.name =name;
        }
        static.sayHello(){
            console.log('hello')
        }
        sayName(){
           console.log('my name is' +this.name)
            return this.name
        }
    }
    class Child extends Parent{
        constructor(name,age){
            super(name);
            this.age =age;
        }
        sayAge(){
            console.log('my age is' +this.age);
            return this.age
        }
    }
    let parent = new Parent('Parent');
    let child = new Child('Child', 18);
    console.log('parent: ', parent); // parent:  Parent {name: "Parent"}
    Parent.sayHello(); // hello
    parent.sayName(); // my name is Parent
    console.log('child: ', child); // child:  Child {name: "Child", age: 18}
    Child.sayHello(); // hello
    child.sayName(); // my name is Child
    child.sayAge(); // my age is 18
    
  • 相关阅读:
    《JAVA多线程编程核心技术》 笔记:第四章、Lock的使用
    服务器负载粗略估算
    spring事务传播性理解
    BlockingQueue 阻塞队列2
    六大原则
    mycat之schema.xml理解
    mycat分库读写分离原理
    sqlservere连接问题
    java代码添加mysql存储过程,触发器
    Amoeba+Mysql实现读写分离+java连接amoeba
  • 原文地址:https://www.cnblogs.com/lrgupup/p/12900227.html
Copyright © 2020-2023  润新知