this、原型鏈、繼承

深入詳解javascript之delete操作符
深入javascript(六):instanceof 運算符
重新理解JS的6種繼承方式
JS 的 new 到底是干什么的?

1.apply、call 、bind有什么作用,什么區別

  • 這三個函數主要作用在于改變this的指向。

  • call:傳遞一個thisArgs參數和一個參數列表,thisArgs 指定了函數在運行期的調用者,也就是函數中的 this 對象,而參數列表會被傳入調用函數中,如:

    var a = {
    
         name:'onepixel', //定義a的屬性
    
        say:function(){ //定義a的方法
            console.log("Hi,I'm function a!");
        }
    };
    
    function b(name){
        console.log("Post params: "+ name);
        console.log("I'm "+ this.name);
        this.say();
    }
    
    b.call(a,'test');
    >>>
    Post params: test
    I'm onepixel
    I'm function a!
    
  • apply:和call效果相似,只是第二個參數傳遞的是數組

     function b(x,y,z){
       console.log(x,y,z);
     }
     b.apply(null,[1,2,3]); // 1 2 3
    
  • bind:ES5引入 bind 的真正目的是為了彌補 call/apply 的不足,由于 call/apply 會對目標函數自動執行,從而導致它無法在事件綁定函數中使用,因為事件綁定函數不需要我們手動執行,它是在事件被觸發時由JS 內部自動執行的。而 bind 在實現改變函數 this 的同時又不會自動執行目標函數
    var obj = {name:'onepixel'};

    /**
    * 給document添加click事件監聽,并綁定onClick函數
    * 通過bind方法設置onClick的this為obj,并傳遞參數p1,p2
    */
     document.addEventListener('click',onClick.bind(obj,'p1','p2'),false);
    
     //當點擊網頁時觸發并執行
     function onClick(a,b){
         console.log(
               this.name, //onepixel
               a, //p1
               b  //p2
         )
     }  
    

2.以下代碼輸出什么?

  var john = { 
    firstName: "John" 
  }
  function func() { 
    alert(this.firstName + ": hi!")
  }
  john.sayHi = func
  john.sayHi()   //john:hi

3.下面代碼輸出什么,為什么

  func() 
  function func() { 
    alert(this)
  }    //代碼輸出為window
  • 因為func函數為全局變量,相當于window.func() 或者是 func.call(undefined)

4.下面代碼輸出什么

  document.addEventListener('click', function(e){
      console.log(this);    //  這個this為document
      setTimeout(function(){
          console.log(this);    // setTimeout、setInterval函數的全局對象為window
      }, 200);
  }, false);

5.下面代碼輸出什么,why

  var john = { 
      firstName: "John" 
  }

  function func() { 
      alert( this.firstName )
  }
  func.call(john)    //  John
  • 因為使用了call方法,該方法將func的this轉向為john

6.以下代碼有什么問題,如何修改

  var module= {
    var _this = this   //  將this賦值給_this
    bind: function(){
      $btn.on('click', function(){
        console.log(this)   //  this 指 $btn
        this.showMsg();    //  修改為_this.showMsg
      })
    },

    showMsg: function(){
      console.log('饑人谷');
    }
  }

7.有如下代碼,解釋Person、 prototype、proto、p、constructor之間的關聯。

   function Person(name){
       this.name = name;
   }
   Person.prototype.sayName = function(){
       console.log('My name is :' + this.name);
   }
   var p = new Person("若愚")
   p.sayName();
  • Person是一個構造函數,當new Person()的時候會創建一個空對象,然后將空對象的__proto__指向prototype,再將返回值賦值給p(實例對象),對象的constructor屬性用于返回創建該對象的函數,也就是我們常說的構造函數

8.上例中,對對象 p可以這樣調用 p.toString()。toString是哪里來的? 畫出原型圖?并解釋什么是原型鏈。

  • p.toString()方法是繼承構造函數Object的原型對象里定義的toString方法,首先p會找自己的toString方法,如果沒有找到,會沿著__proto__屬性繼續到構造函數Person的prototype里找toString方法,如果還未找到,再繼續往Person.prototype的__proto__即Object.prototype找toString方法,最后找到toString()方法。
  • 原型鏈:由于原型對象本身也是對象,而每個javascript對象都有一個原型對象,每個對象都有一個隱藏的proto屬性,原型對象也有自己的原型,而它自己的原型對象又可以有自己的原型,這樣就組成了一條鏈,這個就是原型鏈。在訪問對象的屬性時,如果在對象本身中沒有找到,則會去原型鏈中查找,如果找到,直接返回值,如果整個鏈都遍歷且沒有找到屬性,則返回undefined。原型鏈一般實現為一個鏈表,這樣就可以按照一定的順序來查找。
3704824-d6cbc01eac70a205.png

9.對String做擴展,實現如下方式獲取字符串中頻率最高的字符

    // 方法一: 
    String.prototype.getMostOften = function(){
        var obj = {};
        for(var i = 0; i < this.length; i++){
            if(obj[this[i]]){
                obj[this[i]]++;
            }else{
                obj[this[i]] = 1;
            }
        }

        var count = 0,key;
        for(var k in obj){
            if(obj[k] > count){
                count = obj[k];
                key = k
            }
        }

        return key + ',出現次數:' + count
    }
    
    var str = 'ahbbccdeddddfg';
    var ch = str.getMostOften();
    console.log(ch); //d , 因為d 出現了5次

    //  方法二:
    String.prototype.getMostOften = function(){
        var arr = this.split('');
        var obj = arr.reduce(function(init,value){
            if(init[value]){
                init[value]++;
            }else{
                init[value] = 1;
            }

            return init;
        },{})

        var count = 0,key;
        for(var k in obj){
            if(obj[k] > count){
                count = obj[k];
                key = k;
            }
        }

        return key + ',出現次數:' + count
    }

    
    
    var str = 'ahbbccdeddddfg';
    var ch = str.getMostOften();
    console.log(ch);

10.instanceOf有什么作用?內部邏輯是如何實現的?

instanceof運算符可以用來判斷某個構造函數的prototype屬性是否存在另外一個要檢測對象的原型鏈上。

  function instanceOf(obj,fn){
    var oldpro = obj.__proto__;
    while(oldpro){
      if(oldpro === fn.prototype){
          return true;
          break;
      }else{
          oldpro = oldpro.__proto__;
      }
    }
    return false;
  }

11.繼承有什么作用?

  • 概念:繼承是指一個對象直接使用另一個對象的屬性和方法。
  • 作用:繼承劃分了類的層次性,父類代表的是更一般、更泛化的類,而子類則是更為具體、更為細化;繼承是實現代碼重用、擴展軟件功能的重要手段,子類中與父類完全相同的屬性和方法不必重寫,只需寫出新增或改寫的內容,這就是說子類可以復用父類的內容,不必一切從零開始

12.下面兩種寫法有什么區別?

  //方法1
  function People(name, sex){
      this.name = name;
      this.sex = sex;
      this.printName = function(){
          console.log(this.name);
      }
  }
  var p1 = new People('饑人谷', 2)

  //方法2
  function Person(name, sex){
      this.name = name;
      this.sex = sex;
  }

  Person.prototype.printName = function(){
      console.log(this.name);
  }
  var p1 = new Person('若愚', 27);
  • 區別:同樣都是創建printName方法,方法1的printName方法是在函數Person實例對象里的,方法2是在Person的prototype對象上的。當再創建一個Person實例對象的時候,方法1又將會再創建一個printName方法,占用新的內存,而方法2將一個公用的printName方法寫在原型上,當對象要使用該方法只需到原型鏈里調用就可以了,達到節省內存的效果

13.Object.create 有什么作用?兼容性如何?

  • Object.create() 方法使用指定的原型對象和其屬性創建了一個新的對象。

  • 不支持IE8以下瀏覽器

    function Person(name, age){
        this.name = name;
        this.age = age;
    }
    Person.prototype.sayName = function(){
        console.log(this.name);
    }
    function Male(name, age, sex){
        Person.call(this, name, age);
        this.sex = sex;
    }
    // Male.prototype = new Person(); //該方法同下,代替不兼容Object.create()的使用場景
    Male.prototype = Object.create(Person.prototype);
    Male.prototype.constructor = Male;
    Male.prototype.sayAge = function(){
          console.log(this.age);
    };
    var p1 = new Male('hunger', 20, 'nan');
    p1.sayName();//hunger
    p1.sayAge();//20
    

14.hasOwnProperty有什么作用? 如何使用?

  • hasOwnPerperty是Object.prototype的一個方法,可以判斷一個對象是否包含自定義屬性而不是原型鏈上的屬性,hasOwnProperty是JavaScript中唯一一個處理屬性但是不查找原型鏈的函數

  • 此方法不會檢查對象的原型鏈中是否存在該屬性,該屬性只有是對象本身的一個成員才會返回true

    function Site(){
        this.name = "CodePlayer";
        this.url = "http://www.365mini.com/";
    
        this.sayHello = function(){
            document.writeln("歡迎來到" + this.name);
        };
    }
    
    var obj = {
        engine: "PHP",
        sayHi: function(){
            document.writeln("歡迎訪問" + this.url);
        }
    };
    // 使用對象obj覆蓋Site本身的prototype屬性
    Site.prototype = obj;
    
    var s =  new Site();
    document.writeln( s.hasOwnProperty("name") ); // true
    document.writeln( s.hasOwnProperty("sayHello") ); // true
    // 以下屬性繼承自原型鏈,因此為false
    document.writeln( s.hasOwnProperty("engine") ); // false
    document.writeln( s.hasOwnProperty("sayHi") ); // false
    document.writeln( s.hasOwnProperty("toString") ); // false
    
    // 想要查看對象(包括原型鏈)是否具備指定的屬性,可以使用in操作符
    document.writeln( "engine" in s ); // true
    document.writeln( "sayHi" in s ); // true
    document.writeln( "toString" in s ); // true
    

15.如下代碼中call的作用是什么?

  function Person(name, sex){
      this.name = name;
      this.sex = sex;
  }
  function Male(name, sex, age){
      Person.call(this, name, sex);    //這里的 call 有什么作用
      this.age = age;
  }
  • call的作用是將構造函數Person的this指向Male,使得Male擁有Person的屬性

16.補全代碼,實現繼承

    function Person(name, sex){
        this.name = name;
        this.sex = sex;
    }

    Person.prototype.getName = function(){
        console.log('My name is' + this.name)
    };    

    function Male(name, sex, age){
       Person.call(this,name,sex);
       this.age = age;
    }

    Male.prototype = Object.create(Person.prototype);
    Male.prototype.constructor = Male
    // 兼容寫法:
    // function Temp(){}
    // Temp.prototype = Person.prototype
    // Male.prototype = new Temp()

    Male.prototype.getAge = function(){
        console.log('My age is' + this.age)
    };
    var ruoyu = new Male('若愚', '男', 27);
    ruoyu.printName();
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,882評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,208評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,746評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,666評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,477評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,960評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,047評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,200評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,726評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,617評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,807評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,327評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,049評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,425評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,674評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,432評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,769評論 2 372

推薦閱讀更多精彩內容