JS高級與面向對象

一、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 錨點 定位頁面的某一部分

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 工廠模式類似于現實生活中的工廠可以產生大量相似的商品,去做同樣的事情,實現同樣的效果;這時候需要使用工廠模式。簡單...
    舟漁行舟閱讀 7,827評論 2 17
  • 單例模式 適用場景:可能會在場景中使用到對象,但只有一個實例,加載時并不主動創建,需要時才創建 最常見的單例模式,...
    Obeing閱讀 2,097評論 1 10
  • title: js面向對象date: 2017年8月17日 18:58:05updated: 2017年8月27日...
    lu900618閱讀 581評論 0 2
  • 一、面向過程和面向對象的區別、聯系 1.面向過程編程:注重解決問題的步驟,分析問題需要的每一步,實現函數依次調用。...
    空谷悠閱讀 907評論 1 11
  • 2016.9.9 第6章 原型與面向對象 原型雖然是定義對象的一種很方便的方式,但它的本質依然是函數特性。 使用原...
    如201608閱讀 709評論 0 0