美文网首页JS知识点
JS高级与面向对象

JS高级与面向对象

作者: 福尔摩鸡 | 来源:发表于2017-04-05 23:41 被阅读0次

    一、JavaScript基础知识回顾

    1.1 JavaScript

    1.1.1 javascript是什么?

    JavaScript是一门编程语言,用来操作页面标签和样式。

    1.1.2 javascript的组成

    • ECMAScript:可以为不同种类的宿主环境提供核心的脚本编程能力,因此核心的脚本语言是与任何特定的宿
      主环境分开进行规定的。Web 浏览器对于 ECMAScript 来说是一个宿主环境,但它并不是唯一的宿主环境。
      ECMAScript描述了以下内容:语法、类型、语句、关键字、保留字、运算符、对象。
    • DOM:(Document Object Model 文档对象模型)是 HTML 和 XML 的应用程序接口(API)。DOM 将把
      整个页面规划成由节点层级构成的文档。HTML 或 XML 页面的每个部分都是一个节点的衍生物。用 DOM
      API 可以轻松地删除、添加和替换节点。
    • BOM:(Browser Object Model 浏览器对象模型)可以对浏览器窗口进行访问和操作。

    1.1.3 ECMAScript与JavaScript的关系

    前者是后者的规格,后者是前者的一种实现。

    1.1.4 JavaScript中的数据类型

    • 基本类型:number string boolean null undefined
    • 引用类型:object (Array Date Math(比较特别) RegExp Function Object Error Number String Boolean XMLHttpRequest )
    • 基本类型与引用类型的差别:
      • 存储方式不同:基本类型数据存储在栈stack;引用类型存储在堆heap。
      • 赋值方式不同:基本类型赋值的时候传递的是具体的值;引用类型赋值的时候传递的是内存的地址。

    1.1.5 JavaScript中的语句

    • 分支:if,if else,switch
    • 循环:do while,while,for,for in

    1.2 异常处理

    作用:

    • 防止某些程序出错时影响后面代码的执行。
    • 屏蔽底层的报错细节,从而给用户一个友好提示。
    var abc = 123;
    try{
        var data = false;
        if(!false){
            throw new Error('数据格式异常');
        }
        //try当中的代码一旦发生错误,try当中之后的代码就不再执行了
        console.log(abc);
    }catch(e){
        //只有try当中的代码发生错误,这里才会执行
        console.log(e.message);//表示错误原因
        console.log(e.name);//表示错误类型
    }finally{
        //无论try当中的代码是否执行,这里都会执行
        console.log(abc);
    }
    

    二、面向对象

    2.1 面向对象概述

    2.1.1 什么是对象

    所谓的对象就是某种事物,万物皆对象。

    用程序的方式描述对象:属性+行为。

    2.1.2 对象创建方式

    • 字面量:各种数据类型的字面量表示。

      var obj1 = {
        username : '张三',
        age : 12,
        gender : 'male'
      };
      
    • 构造函数:内置对象和自定义对象。

      var obj2 = new Object();
      obj2.username = '李四';
      obj2.age = 13;
      obj2.gender = 'female';
      

      如果构造函数不需要传递参数,那么后面的括号可以省略。

      var obj = new Object();
      var obj = new Object;
      

    2.1.3 属性的访问方式

    • 对象名.属性名称
    • 对象名['属性名称']

    两种方式的区别:方括号的方式可以使用变量。

    2.1.4 实例化的本质

    构造函数实例化对象本质上做了什么工作?

    1. 开辟堆内存用来存储实例中数据(属性和方法)。
    2. 用this指向该区域。
    3. 通过this向该区域中放置数据。
    4. 返回this
    function Foo(info){
            // 构造函数中的this指的是构造函数所创建的实例对象
            this.info = info;
            this.showInfo = function(){
                // 实例方法中的this指向方法的调用者(实例对象本身)
                console.log(this.info);
            }
            // 构造函数的默认返回值就是this
        }
        var foo = new Foo('tom');
        foo.showInfo();
    
        var foo1 = new Foo('jerry');
        foo1.showInfo();
    

    2.1.5 构造函数的返回值

    • 构造函数如果显示的返回基本数据类型,那么和不返回等效。
    • 构造函数如果显示的返回引用数据类型,那么就以此为准,就不再返回默认的this了。
    function Person(name){
        this.name = name;
        return 123;         //输出:Person {name: "zhangsan"}
        return 'hello';     //输出:Person {name: "zhangsan"}
    
        return {
            name : 'lisi',
            age : 12
        };                  //输出:Object {name: "lisi", age: 12}
        return [1,2,3];     //输出:[1,2,3]
    }
    var p = new Person('zhangsan');
    console.log(p);
    

    2.1.6 对象原型

    JavaScript中对象的本质:无序的键值对集合。

    原型:实现数据共享(实例对象之间进行数据共享)。

    function Foo(info){
    this.info = info;
    this.showInfo = function(){
    console.log(this.info);
    }
    }
    var f1 = new Foo('tom');
    var f2 = new Foo('jerry');
    console.log(f1.showInfo === f2.showInfo);//false
    -------------------------------------------------------------------------------
    function fn(){
        console.log(this.name);
    }
    function Person(name,age){
        this.name = name;
        this.age = age;
        this.showName = fn;
    }
    var p1 = new Person('zhangsan');
    var p2 = new Person('lisi');
    console.log(p1.showName === p2.showName);//true
    

    2.1.7 原型分析

    原型:函数都有一个原型属性prototype,该属性值本质上也是对象(实际就是Object的实例)。

    原型的作用:实现数据共享(实例对象之间进行共享);实现继承。

    __proto__:构造函数产生的实例对象都有一个属性__proto__,该属性不是标准属性,不可以在编程中使用,实际上该属性是浏览器内部使用的,该属性和构造函数中的prototype指向相同。

    __proto__属性在实例对象中,prototype属性在构造函数中,这两个属性的指向是相同的。

    function Person(name,age){
        this.name = name;
        this.age = age;
    }
    
    Person.prototype.showName = function(){
        console.log(this.name);
    }
    Person.prototype.showAge = function(){
        console.log(this.age);
    }
    Person.prototype.flag = 123;
    Person.prototype.arr = ['red','green','blue'];
    
    var p1 = new Person('tom',12);
    p1.flag = 456;
    p1.arr.push('pink');
    var p2 = new Person('jerry',13);
    
    console.log(p1.flag,p2.flag);   //456 123
    console.log(p1.arr,p2.arr);     //["red", "green", "blue", "pink"] ["red", "green", "blue", "pink"]
    
    //解释:
    //通过对象.属性名称=值  这种做法会向对象中添加一个属性
    //但是obj.arr.push(123); 这种结构不会再obj中添加属性,而会obj.arr数组中添加一项数据
    

    2.2 面向过程与面向对象

    2.2.1 相关概念

    • 面向对象是一种编程模式,就是以对象的方式写代码。

      三大特性:封装、继承那个、多态。

    • 面向过程的编程模式的缺点:团队开发容易产生命名冲突;不方便代码的重用;可维护性差。

    • JavaScript面向对象相关概念:

      1. 构造函数
      2. 实例对象
      3. 原型

    2.2.2 面向对象开发

    //实现如下功能:点击一个按钮改变div的背景色
    //用面向对象的风格封装(构造函数+原型)
    
    function ChangeColor(btnId,divId){
        this.btn = document.getElementById(btnId);
        this.div = document.getElementById(divId);
    }
    
    ChangeColor.prototype.init = function(){
        // 原型方法中的this指的是该原型所属的构造函数的实例化对象,实际上与构造函数中的this指向相同
        var that = this;//缓存实例对象
        this.btn.onclick = function(){
            // 这里的this是绑定事件函数的DOM对象
            that.div.style.backgroundColor = 'yellow';
        }
    }
    
    onload = function(){
        var cc = new ChangeColor('btn','div1');
        cc.init();
    }
    
    //不同的this场景:
    //1、构造函数中的this
    //2、原型方法中的this
    //3、事件方法中的this
    
    //1) 构造函数中的this和原型方法中的this指向相同:都是指向实例对象
    //2)事件方法中的this指的是绑定事件的对象
    

    2.2.3 对象中属性的判断

    • in:判断对象中是否存在某个属性(属性在实例对象和原型对象都可以)。
    • hasOwnProperty():判断属性是否在实例对象上。
    //小测试:
    if('a' in window) {
        var a = 123
        console.log(a);
    }
    //输出:123
    //考点:
    //1.全局作用域中的变量和函数都是window对象的成员
    //2.预解析
    //3.js中没有块级作用域
    
    //实现一份方法,判断某个属性是否在原型上
    function check(attr,obj){
        if(attr in obj && !obj.hasOwnProperty(attr)){
            return true;
        }else{
            return false;
        }
    }
    

    2.3 构造函数、原型与实例的关系

    2.3.1 构造函数、原型与实例的关系

    1. 构造函数中都有原型属性prototype,该属性值本质也是对象(Object的实例对象)
    2. 原型对象中都有一个属性constructor,该属性指向原型所属的构造函数
    3. 实例对象中都有一个属性__proto__,该属性不是标准属性,不可以在编程中使用,实际上是浏览器内部使用的,并且该属性指向原型对象。

    2.3.2 原型链

    • 原型链:实例对象和原型对象之间形成的有限链式结构,该链式结构通过__proto__连接起来,用于实现继承和共享属性。

    • 对象是有原型对象的,原型对象也有原型对象,原型对象也有原型对象,对象的原型对象一直往上找,会找到一个null。

      var obj = new Object();
      // obj -> Object.prototype -> null
      
      var arr = new Array();
      // arr -> Array.prototype -> Object.prototype -> null
      
      var date = new Date();
      // date -> Date.prototype -> Object.prototype -> null
      
    • 原型链的结构可以通过重置原型对象的方式来修改。

      function Foo1(info){
          this.info = info;
      }
      Foo2.prototype = new Foo1('tom');
      //Foo2.prototype.constructor = Foo1;
      function Foo2(info){
          this.info = info;
      }
      Foo3.prototype = new Foo2('jerry');
      //Foo3.prototype.constructor = Foo2;
      function Foo3(info){
          this.info = info;
      }
      var f = new Foo3('spike');
      console.dir(f);
      
      // f -> new Foo2('jerry') -> new Foo1('tom') -> Foo1.prototype -> Object.prototype -> null
      

    2.4 继承

    继承:别人的拿过来,自己的还是自己的。可以通过修改原型的指向来实现。

    2.4.1 原型继承

    function Animal() {
        this.name = '动物';
    }
    
    function Tiger(color) {
        this.color = color;
    }
    Tiger.prototype = new Animal();
    var tiger = new Tiger('黄色');
    console.log(tiger.name);
    console.log(tiger.color);
    

    缺点:没有办法给基础过来的属性赋值,而不影响所有的实例。继承过来的引用类型的数据,所有的实例时共享的。

    2.4.2 借用构造函数继承

    • call和apply的基本使用:

      1. call和apply可以调用函数。
      2. 改变所调用函数内部的this指向。
      3. 在非严格模式下,普通函数中this是window;在严格模式下,普通函数中this是undefined。
    • 借用构造函数继承:

      function Person(name,favour){
          this.name = name;
          this.favour = favour;
      }
      
      Person.prototype.showName = function(){
          console.log(this.name);
      }
      
      function Student(num,name,favour){
          // 这里的this是Student构造函数的实例
          // Person.call(this,name,favour);
          Person.apply(this,[name,favour]);
          this.num = num;
      }
      
      var stu1 = new Student(1,'zhangsan',['coding']);
      stu1.favour.push('swimming');
      var stu2 = new Student(2,'lisi',['dancing']);
      
      console.dir(stu1);
      console.dir(stu2);
      stu1.showName();
      

      缺点:没有办法继承父级构造函数原型上的成员。

    2.4.3 组合继承

    function Person(name,age){
        this.name = name;
        this.age = age;
    }
    Person.prototype.show=function(){
        console.log(this.name+"今年"+this.age+"岁了");
    }
    Person.prototype.flag=1;
    
    function Teacher(name,age,level){
        Person.call(this,name,age);
        this.level=level;
    }
    Teacher.prototype=new Person();
    
    var t1 = new Teacher("张三",33,"T5");
    var t2 = new Teacher("李四",30,"T4");
    t1.show();
    

    2.5 Object.create的基本使用

    //ES5新特性,方法的作用:创建对象
    var create = function(obj){
        if(Object.create){
            return Object.create(obj);
        }else{
            function F(){}
            F.prototype = obj;
            return new F();
        }
    }
    

    2.6 属性的复制

    2.6.1 浅拷贝

    var obj = {};
    var obj1 = {
        username : 'zhangsan',
        age : 12,
        gender : 'male'
    }
    function extend(des,origin){
        for(var key in origin){
            des[key] = origin[key];
        }
    }
    extend(obj,obj1);
    console.log(obj);
    

    2.6.2 深拷贝

    function foo(set){
        var defaultSettings = {
            width : '100',
            height : '200',
            backgroundColor : 'gray',
            sets : {
                flag : 12,
                abc : 'message'
            }
        }
        var obj = {
            www : 'www'
        }
        var obj1 = {
            qqq : 'qqq'
        }
        $.extend(true,defaultSettings,set,obj,obj1);
        console.dir(defaultSettings);
        console.log(defaultSettings.width);
        console.log(defaultSettings.sets.flag);
        console.log(defaultSettings.sets.abc);
    }
    
    var settings = {
        width : '1000',
        sets : {
            flag : 123,
        }
    }
    foo(settings);
    

    2.7 函数

    2.7.1 函数的原型链

    • Function
      1. 所有的函数都是Function的实例。
      2. Funciton也是一个函数。

    2.7.2 函数的三种角色

    1. 构造函数
    2. 普通函数
    3. 函数作为对象
    function Foo(){}
    var foo = new Foo();    //构造函数
    Foo();                  //普通函数
    Foo.info = 'hello';     //函数作为对象
    

    函数到底是哪种角色,取决于函数的调用方式

    2.7.3 函数的定义方式

    • 系统函数(类库、库函数)

    • 自定义函数

      1. 函数声明

        function foo(){
           console.log(123);
        }
        
      2. 函数表达式

        var fn = function(){
            console.log(456);
        }
        fn();
        
      3. new Function()

        var fn1 = new Function('console.log(789);');//需要把字符串转成js代码并执行,性能没有前两者好
        fn1();
        

      区别

      1. 函数声明是在预解析阶段创建的,而函数表达式是在程序执行阶段创建的。
      2. 函数声明只能在全局或者函数内部定义,而函数表达式只能在表达式中定义。
    • 函数都是对象,但对象不一定是函数。

    • Math不是函数,而是对象

    2.7.4 this的不同指向场景

    • 函数的调用方式:(函数中的this指向取决与函数的调用方式)

      1. 构造函数
      2. 普通函数
      3. 对象方法
      4. call和apply调用(bind)
    • this的不同指向:

      1. 构造函数中的this指向实例对象
      2. 原型方法中的this指向实例对象,与构造函数中的this指向相同
      3. 在非严格模式下,普通函数中的this指向window,在严格模式下,普通函数中的this指向undefined
      4. 对象方法中的this就是调用方法的对象
      5. 事件方法中的this指的是绑定事件的对象
      6. 定时函数中的this指的是window
      7. call或apply所调用的函数中的this就是call或apply中的第一个参数(该参数必须是引用类型)
    • bind的基本用法:

      • bind方法是ES5的新特性(函数的柯里化)
      • bind用来改变函数内部的this指向,但是不调用函数,并且bind会返回一个新函数(其实还是原来的函数内容,只是this改变为bind中的第一个参数,该参数必须为引用类型)
      var inner = function(a,b){
          console.log(a+b);
      }
      var newInner = inner.bind({info:'hello'},12,13);
      setTimeout(newInner,1000);
      

    2.7.5 高阶函数

    高阶函数

    • 作为参数的函数

      function foo(fn) {
        var data = {
            info: 'hello'
        }
        fn(data);
      }
      var fn = function(data) {
        console.log(data.info);
      };
      foo(fn);
      
    • 作为返回值的函数(闭包)

      function foo(){
        var num = 1;
        return function(){
            return num++;
        }
      }
      var fn = foo();
      var r1 = fn();
      var r2 = fn();
      console.log(r1,r2);
      

    2.8 对象加深

    2.8.1 对象的体系结构

    1. 所有的实例对象都有一个__proto__属性,该属性指向产生实例对象的构造函数的原型。
    2. 所有的构造函数都有一个prototype属性,该属性本质上也是一个对象(Object的实例对象)
    3. 所有的原型对象都有一个constructor属性,该属性指向原型所属的构造函数。
    4. 原型对象中有一个__proto__属性,该属性指向Object.prototype(Object的原型对象中没有__proto__,因为这里就是原型链的终点)
    5. 所有的函数都是Function的实例对象。
    6. Function函数本身也是它自己的实例对象(也就是Function.__proto__===Function.prototype)

    2.8.2 基本类型与引用类型深入理解

    • 基本类型

      var num = 123
      function foo(data){
        data = '456';
        return data;
      }
      var ret = foo(num);
      console.log(ret,num);//456 123
      
    • 引用类型

      var arr = [1,2,3];
      function foo(data){
        data.push(4);
        return data;
      }
      var ret = foo(arr);
      console.log(ret,arr);//[1, 2, 3, 4] [1, 2, 3, 4]
      

    2.8.3 标准库

    • 常用对象:Object、Array、Date、RegExp、Math、Function、Error
    • 包装对象:Number、String、Boolean

    2.8.4 类数组(关联数组)详解

    • 类数组:

      var obj = {
        0 : 'qqq',
        1 : 'www',
        2 : 'eee',
        length : 3
      }
      
    • 类数组转数组:

      var arr = [].slice.call(obj,0);
      
    • delete的用法:

      var obj = {
        info : 'abc',
        username : 'lisi'
      }
      delete obj.info;
      console.log(obj);//Object {username: "lisi"}
      var flag = 123;
      delete flag;
      console.log(flag);//123
      
      1. delete的作用就是删除对象的属性。
      2. 全局作用域中var声明的变量,delete无法删除,但是不用var声明的全局变量可以delete删除。
    • 求数组中的最大值:

      //排序
      var arr = [12321,234,99999999,4454,12,454545,343,34,342];
      arr.sort(function(a,b){
          return b - a;
      });
      console.log(arr);//[99999999, 454545, 12321, 4454, 343, 342, 234, 34, 12]
      
      //对象中的Math方法
      var max = Math.max(123,23,4324,45,4,645,6,45645);
      console.log(max);
      
      //借用对象的方法
      var max = Math.max.apply(null,arr);
      console.log(max);
      

      call和apply的应用场景

      1. 调用函数
      2. 改变所调用函数的内部this指向
      3. 转换类数组
      4. 借用别的对象方法

    2.9 递归

    2.9.1 递归的执行原理

    function fn(n){
        if(n == 1){
            console.log('递归结束' + n);
            return 1;
        }else{
            console.log('递归前' + n);
            var ret = n * fn(n-1);
            console.log('递归后' + n);
            return ret;
        }
    }
    var ret = fn(5);
    console.log(ret);
    
    /* 输出结果:
    递归前5
    递归前4
    递归前3
    递归前2
    递归结束1
    递归后2
    递归后3
    递归后4
    递归后5
    120
    */
    

    2.9.2 递归的应用

    function getChildNodes(node, arr) {
        for (var i = 0; i < node.childNodes.length; i++) {
            var subNode = node.childNodes[i];
            //如果子节点是元素类型就放到数组中
            if (subNode.nodeType == 1) {
                arr.push(subNode);
                //以当前子节点作为新的父节点继续递归
                getChildNodes(subNode, arr);
            }
        }
    }
    window.onload = function () {
        var arr = [];
        var div = document.getElementById('div');
        getChildNodes(div, arr);
        console.log(arr);
    }
    

    2.9.3 jQuery实例化过程

    $(function(){
            // var ret = $('.active');
            // console.dir(ret);
            // ret.html('123').css('backgroundColor','green');
    
            // var aDiv = document.getElementsByTagName('div')[0];
            // console.dir(aDiv);
    
            // // ret[0];
            // console.log(ret.get(0) === aDiv);
    
            function jQuery(selector){
               return new jQuery.prototype.init(selector);
            }
            jQuery.prototype = {
                constructor : jQuery,
                html : function(){
                    console.log(123);
                    return this;
                },
                css : function(){
                    console.log(456);
                    return this;
                },
                init : function(selector){
                    // 实现选择器功能
                    // div .active #div1  div span  .active div span
                    // Sizzle
                    var aDiv = document.getElementsByTagName(selector);
                    // 把每一个div都放到this中,那么this就是一个类数组
                    [].push.apply(this,aDiv);
                    this.length = aDiv.length;
                }
            }
            jQuery.prototype.init.prototype = jQuery.prototype;
    
            var obj = jQuery('div');
            obj.html('123').css(456);
    
            // obj.html('hello').css();
            $('div').css('width');//获取某个样式值
            $('div').css('width','100px');//设置样式值
            $('div').css({
                width : '100px',
                height : '100px'
            });
            $('div').css(['width','height']);//{width : 100px,height : 100px}
    
    
        });
    //待整理
    

    2.10 作用域与闭包

    2.10.1 作用域

    作用域:指的是变量的作用范围。

    • 全局作用域
    • 函数作用域
    • js没有块级作用域

    作用域链:链是一个对象列表(list of objects) ,用以检索上下文代码中出现的标识符(identifiers) 。标示符可以理解为变量名称、函数声明和普通参数。作用域链包括活动对象和父级变量对象。

    • 函数内层作用域可以访问外层作用,但是反过来不可以。

    2.10.2 预解析

    JavaScript解析器在执行代码的时候分为两个阶段:

    1. 预解析
      • 全局预解析(所有的变量和函数声明都会提前;同名的函数和变量函数的优先级高)
      • 函数内部预解析(所有的变量、函数和形参都会预解析,优先级:函数 > 形参 > 变量)
    2. 从上到下逐行执行

    先预解析全局作用域,然后执行全局作用域中的代码,在执行全局代码的过程中遇到函数调用就会先进行函数预解析,然后再执行函数内的代码。

    2.10.3 闭包

    闭包是一系列代码块(在ECMAScript中是函数),并且静态保存所有父级的作用域。通过这些保存的作用域来搜寻到函数中的自由变量。

    当一个函数在自身函数体内需要引用一个变量,但是这个变量并没有在函数内部声明(或者也不是某个参数名),那么这个变量就可以称为自由变量[free variable]。

    闭包

    • 封闭的区域
    • 函数的嵌套形成闭包(内层函数和内层函数所处的作用域)
    • 闭包可以操作函数内部的变量(间接的)

    闭包的作用

    • 可以缓存中间状态值
    • 延长变量的生命周期
    var arr = [];
    for (var i = 0; i < 3; i++) {
        arr[i] = (function(num){
            return function(){
                console.log(num);
            }
        })(i);
    }
    arr[0]();   //0
    arr[1]();   //1
    arr[2]();   //2
    

    闭包的应用

    onload = function(){
        var aInput = document.getElementsByTagName('input');
        for (var i = 0; i < aInput.length; i++) {
            // aInput[i].onclick = (function(){
            //     var num = 0;
            //     return function(){
            //         ++num;
            //         console.log(num);
            //     }
            // })();
            aInput[i].onclick = function(){
                this.num?++this.num:this.num=1;
                console.log(this.num);
                console.dir(this);
            }
        }
    }
    

    2.10.4 对象排序

    function sortFn(sortName){
        return function(a,b){
            var v1 = a[sortName];
            var v2 = b[sortName];
            if(v1 > v2){
                return 1;
            }else if(v1 < v2){
                return -1;
            }else{
                return 0;
            }
        }
    }
    

    2.11 事件

    2.11.1 函数相关属性补充

    • arguments 表示实参的集合
    • length 形参的个数
    • caller 函数的调用者
    • name 函数的名称
    • arguments.callee 表示函数本身,但是不推荐使用

    2.11.2 事件处理机制

    • 浏览器本身是单线程还是多线程?多线程(多进程)
      1. 页面标签的渲染
      2. 网络通信
      3. 解析js的运行
    • js的运行是单线程的
    • 事件队列(队列中放什么?任务(实际上就是函数))
      1. 定时函数(延时时间到了)
      2. 事件函数(对应的事件触发)
      3. Ajax的回调函数(接收到服务器完整的数据(readyState值发生变化的时候))
    • 事件队列中任务执行的条件:
      1. 主线程空闲
      2. 满足任务的触发条件

    2.11.3 事件绑定方式

    • 行内绑定

      <div onclick="fn3();">
          <div onclick="fn2();">
              <div onclick="fn1();">点击</div>
          </div>
      </div> 
      
    • 给DOM元素直接绑定 btn.onclick

      div.onclick = function(){
        console.log(1);
      }
      
    • addEventListener / attachEvent

      div.addEventListener('click',function(){
        console.log(11);
      },false)
      

    2.11.4 阻止冒泡与阻止默认行为

    • 在原生js中,return false只能阻止默认行为,不能阻止冒泡;只能阻止btn.onclick这种方式绑定的事件,不能阻止addEventListener绑定的事件。
    • 在jQuery中,return false既可以阻止冒泡也可以阻止默认行为。

    2.11.5 自定义事件

    • 注册事件

      function addEvent(obj,type,fn){
          obj.arrs = obj.arrs || {};
          obj.arrs[type] = obj.arrs[type] || [];
          obj.arrs[type].push(fn);
      }
      var obj = {};
      addEvent(obj,'abc',function(){
          console.log('abc');
      });
      addEvent(obj,'abc',function(){
          console.log('abc1');
      });
      addEvent(obj,'hi',function(){
          console.log('hi');
      });
      
    • 触发事件

      function fireEvent(obj,type){
          var fnList = obj.arrs[type];
          for (var i = 0; i < fnList.length; i++) {
              fnList[i]();
          }
      }
      fireEvent(obj,'hi');
      

    2.12 正则

    2.12.1 正则相关API

    • 正则的API:

      1. test

        var reg = /\d/;
        console.log(reg.test('123'));
        
      2. exec

        var str = 'adsfasdf123asdfasdf21312sfdsadfad';
        var reg = /\d+/g;
        // var ret = reg.exec(str);
        // console.log(ret);
        var result = null;
        while((result = reg.exec(str)) != null) {
            console.log("Matched `" + result[0] +
                  "' at position " + result.index +
                  " next search begins at position " + reg.lastIndex);
        }
        
    • 字符串API:

      1. search:查询匹配字符串的索引

        var str = 'dsdaf123asdfasdf';
        console.log(str.search('123'));
        console.log(str.search(/\d+/));
        
      2. match

        //从字符串中找出数字
        var str = '1212adsfasdf123asdfasd234fqewrqew3434rqwerw54qerqwerqwer21321';
        console.log(str.match(/\d+/g));
        
      3. split

        var str = 'zhangsan:12:male;lisi:13:female';
        var arr = str.split(';');
        for (var i = 0; i < arr.length; i++) {
           var item = arr[i].split(':');
           console.log(item[0]);
           console.log(item[1]);
           console.log(item[2]);
        }
        
        var str = 'asdfasdfasdf123asdfas4545dfads';
        var arr = str.split(/\d+/g);
        console.log(arr);
        
      4. replace

        var str = 'adsfasdf123asdfasdf21312sfdsadfad';
        str = str.replace(/\d+/g,'***');
        console.log(str);
        
    • 在非全局匹配模式下,str.match(reg)reg.exec(str)的作用等效。

    2.12.2 正则的规则

    • 元字符:

    三、面试题

    3.1 ==和===相关的比较问题

    [] ==![]        //true 
    [1] == [1]      //false 
    [1] == ![1]     //false
    

    比较规则:

    1. 对象之间的比较是内存地址的比较
    2. 单个空对象转成布尔值是true
    3. 空数组与布尔值的比较会转换成数值的比较(空数组会转化成0)
    4. 转成false的情况:false null '' undefined 0 NaN

    3.2 in使用中的问题

    3.2.1 变量声明时的问题

    console.log('a' in window); //true
    if('a' in window){
        var a = 123; 
        console.log(a);
    }
    
    console.log('a' in window); //false
    if('a' in window){
        a = 123; 
        console.log(a);
    }
    
    • 不使用var不会预解析,但是也会向window中添加属性。

    3.2.2 window中的undefined

    console.log(a in window); //true
    if(a in window){
        var a = 123; 
        console.log(a);
    }
    
    • 不加引号,a是undefined,window中本身就有一个属性undefined,并且undefined的值也是undefined。

    3.3 以下代码的输出结果是什么?

    var a = {n:1};
    var b = a;
    a.x = a = {n:2};    //运算符的优先级 .的优先级最高  赋值操作是从右向左运算的
    console.log(a.x);   //undefined
    console.log(b.x);   //{n:2}
    

    考点:

    1. 基本类型和引用类型
    2. 引用类型变量和对象属性(在内存实际上就是内存地址)
    3. 运算符的优先级.的优先级最高 ,赋值操作是从右向左运算的

    3.4 下列代码输出结果是什么?

    var a = {name:'zhangsan'}; 
    var b = {age : 26}; 
    var arr = []; 
    arr[a] = 123; 
    arr[b] = 456; 
    console.log(arr);//Array[0] -->[object Object]:456
    

    数组也是对象

    对象属性的访问方式

    Object的toString方法作用:把构造函数转成这种形式的字符串:[object Object]

    3.5 跨域解决方案有哪些?

    • jsonp
    • cors
    • 反向代理
    • flash插件

    3.6 DNS解析过程是什么?

    • DNS Domain Name System : 负责域名和IP地址的映射关系
    • 域名解析的规则:先去本机的hosts文件中查找IP,如果没有找到,就去公网的DNS服务器查找,如果还没有找到,那就无法上网;如果在hosts文件中找到了,那么就返回ip,就不再去公网查找了

    3.7 前端有多少种方式可以发送请求?

    1)浏览器地址直接输入url
    2)表单的action属性
    3)a标签href属性
    4)img的src属性
    5)script的src属性
    6)link标签的href属性
    7)iframe的src属性
    8)Ajax发送请求
    9)postMessage h5新的API
    10)flash插件也可以
    11)location.href

    url的规范格式
    scheme://host:port/path?query#fragment
    echeme 表示协议 http https ftp file ssh
    host 表示域名或者IP地址
    port 端口 用来确定计算机上的具体某个网络应用程序
    path 域名之后,?之前的内容 /abc/qqq/rrr
    query 查询字符串,作用是向服务器传递数据,格式:键=值&键=值
    fragment hash 锚点 定位页面的某一部分

    相关文章

      网友评论

        本文标题:JS高级与面向对象

        本文链接:https://www.haomeiwen.com/subject/stixattx.html