關于 this_原型鏈_繼承 相關問題總結

關于this

1- apply、call 、bind的作用和區別

  • apply、call 、bind都有改變this值的作用,
    apply和call的用法區別就在于第二個參數,apply接受的第二個參數是數組,而call第二個參數接受的是不定參。
    bind的參數和call一樣,但是bind是返回一個新的函數,并不是立即調用,可以在任何時候去調用。(bind能夠綁定參數的情況下,再給已經被bind過的結果函數傳參數,參數沒有作用,在使用bind的時候傳進去的參數才有效,后面使用該返回的函數時,只是調用。但是后面傳入的參數會在Arguments里體現。但是如果在綁定當時沒有傳入參數,而是在調用的時候再傳參數,此時的參數是有作用的。)看例子:
function a(xx, yy) {     
console.log(xx, yy);     
console.log(this);     
console.log(arguments);
} 
var thisObj = {name:'haha'};

a.apply(null, [5, 55]); //第一個參數不設置,不改變原this指向
a.call(thisObj, 5, 55); //設置第一個參數,該方法里的this改變成thisObj
var b = a.bind(null, 5, 55); //返回一個新函數
b();

這些方法主要的作用是在一些本身不具備某些方法時,可以借用其他對象的方法來完成。例如:

var nodes = document.getElementsByClass('item'); //得到一個類數組對象
//我想獲取數值最大的那個對象
Arrary.prototype.max.apply(null, nodes); //借用Arrary的方法,將我需要的結果算出來

2- 以下代碼輸出什么

var john = { 
   firstName: "John" 
}
function func() {
   alert(this.firstName + ": hi!")
}
john.sayHi = func
john.sayHi()
  • 輸出: John: hi!
  • 原因:將函數func賦值給sayHi,sayHi也就是一個函數了,執行此函數,這里面的this就是john這個對象

3- 下面代碼輸出什么,及原因

func() 
function func() {
    alert(this)
}
  • 輸出: Object window
  • 原因:因為函數聲明會前置,所以在聲明前調用也是可以的,因為是在全局環境下調用,相當于window.func(),所以this的值是window。

4- 下面代碼輸出結果

document.addEventListener('click', function(e){ 
    console.log(this); //document ,執行click方法的是document
    setTimeout(function(){
        console.log(this); //Window  setTimeout方法的調用者是Window
    }, 200);
}, false);
  • 輸出:
    document
    window
  • 原因:事件處理函數中的this指的是其對應的dom對象,setTimeout中的this指的是window

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

var john = {
  firstName: "John" 
}

function func() {
  alert( this.firstName )
}
func.call(john)
  • 輸出: John
  • 原因: func.call()中傳入了對象john,因此將func中this的值設置為了對象john

6- 下面代碼有什么問題,怎么來修改

var module= {
  bind: function(){
   $btn.on('click', function(){
    console.log(this) //this指什么
    this.showMsg(); 
 }) 
},

 showMsg: function(){
    console.log('饑人谷');
  }
}
  • 問題:事件處理函數中的this指的是該事件處理函數綁定的對象,即$btn,因此該對象沒有showMsg()方法
  • 修改:在bind內部設置一個變量將this保存下來,這樣在事件處理函數中使用該變量來調用showMsg方法
var module= {
  bind: function(){
    var _this = this;
    $btn.on('click', function(){
      console.log(this) //this指什么
      _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構造函數創建之后有一個prototype屬性是一個對象,這個prototype對象上有一個constructor屬性是指向Person構造函數的。當實例化一個p時,首先創建了一個空對象,并把這個對象的proto屬性指向Person.prototype,然后將實例對象傳入構造函數執行函數,最后返回實例對象。當實例p.sayName()時,先在自己的屬性中找,如果沒有找到就在proto指向的原型上找,如果找到了就執行,沒有找到就繼續向上找,直到最頂層的null。

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

  • 原型鏈: 每個構造函數都有一個原型對象,原型對象都包含一個指向構造函數的指針,而實例都包含一個指向原型對象的內部指針.如果讓原型對象等于另一個類型的實例,則原型對象將包含一個指向另一個原型的指針,相應的另一個原型也包含著一個指向另一個構造函數的指針.如此層層遞進,就構成了實例與原型的鏈條,即原型鏈

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

var str = 'ahbbccdeddddfg';
var ch = str.getMostOften();
console.log(ch); //d , 因為d 出現了5次

結果:

var str = 'ahbbccdeddddfg';

String.prototype.getMostOften = function(){
    var maxKey;
    var countArr = this.split("");
    var countObj = {};
    var i = 0;
    //計算每個字符出現的次數
    for(i; i < countArr.length; i++){
        if(countObj[countArr[i]]){
            countObj[countArr[i]] += 1;
        }
        else{
            countObj[countArr[i]] = 1;
        }
    }
    console.log(countObj);
    var sortNum = 0;
    for(var key in countObj){
        if(countObj[key] > sortNum){
            sortNum = countObj[key];
            maxKey = key;
        }
    }
    return maxKey;
};


var ch = str.getMostOften();
console.log(ch); //d , 因為d 出現了5次

10- instanceOf的作用 ,內部邏輯是如何實現的

  • 使用 object instanceof constructor
  • 作用:檢測 constructor.prototype 是否存在于參數 object 的原型鏈上
  • 內部實現邏輯:每個實例都包含一個指向原型對象的內部指針(proto),通過該指針可以找到其原型鏈上的所有內容,因此可以檢測 constructor.prototype 是否存在于參數 object 的原型鏈上.如:
function _instanceof(A, B) {
    var O = B.prototype;// 取B的prototype
    A = A.__proto__;// 取A的__proto__
    while (true) {
        //Object.prototype.__proto__ === null
        if (A === null)
            return false;
        if (O === A)// 當 O 嚴格等于 A 時,返回 true
            return true;
        A = A.__proto__;
    }

繼承相關

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);
  • 方法1:將printName方法放在了構造函數中,但是由于使用了匿名函數,因此每個實例的printName方法都是不同的(盡管功能相同,但每個實例的printName方法都會占用內存空間),并沒有實現代碼的復用
  • 方法2:將printName方法放在了Person的原型對象中,當Person的實例調用printName方法時,會沿著原型鏈,找到Person的原型對象,使用Person的原型對象中的printName方法,因此,盡管每個Person實例都可以調用printName方法,但是這些printName方法都指的是Person的原型對象中的printName方法.實現了代碼的復用

13- Object.create 的作用,及兼容性

  • Object.creat()是創建一個擁有指定原型和若干個指定屬性的對象。
    語法:Object.create(proto,[propertiesObject])
//創建一個空對象
var o = {};
var o = Object.create(Object.prototype);

//創建一個帶有屬性的對象
var o = Object.create(Object.prototype,{ p:{value:88 } } );
var o = {
  p:88
}

//創建一個實例
function Person(){
}
var o = new Person();
var o = Object.create(Person.prototype);
  • Object.Create()兼容性:

14- hasOwnProperty的作用,及如何使用

  • hasOwnProperty這個方法可以用來檢測一個對象是否含有特定的自身屬性(和方法),該方法會忽略掉那些從原型鏈上繼承到的屬性(和方法)。
  • 使用: obj.hasOwnProperty(prop),prop指要檢測的屬性,可以是字符串或者Symbol,返回一個true或false。

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傳入,這樣實例對象上就會有name和sex屬性

16- 通過補全代碼來實現繼承

function Person(name, sex){
    // todo ...
}

Person.prototype.getName = function(){
    // todo ...
};

 function Male(name, sex, age){
    //todo ...
}

//todo ...
Male.prototype.getAge = function(){
    //todo ...
};

var ruoyu = new Male('若愚', '男', 27);
ruoyu.printName();

完整:

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

Person.prototype.getName = function(){
    return this.name;
};

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

Male.prototype = Object.create(Person.prototype); //繼承Person的原型

/**
** 自定義方法寫在繼承之后
**/
Male.prototype.getAge = function(){
    console.log(this.age);
    return this.age;
    
};

Male.prototype.printName = function(){
    console.log(this.getName());
    return this.getName();
    
};

var ruoyu = new Male('若愚', '男', 27);
ruoyu.printName();
- 其他文章參考學習
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容