高級(jí)2-this_原型鏈_繼承

this 相關(guān)問題

問題1: apply、call 有什么作用,什么區(qū)別

Javascript的每個(gè)Function對(duì)象中有一個(gè)apply方法:
function.apply([thisObj[,argArray]])
還有一個(gè)類似功能的call方法:
function.call([thisObj[,arg1[, arg2[, [,.argN]]]]])

  • 它們各自的定義:
    apply:應(yīng)用某一對(duì)象的一個(gè)方法,用另一個(gè)對(duì)象替換當(dāng)前對(duì)象。
    call:調(diào)用一個(gè)對(duì)象的一個(gè)方法,以另一個(gè)對(duì)象替換當(dāng)前對(duì)象。

  • 它們的共同之處:
    都“可以用來代替另一個(gè)對(duì)象調(diào)用一個(gè)方法,將一個(gè)函數(shù)的對(duì)象上下文從初始的上下文改變?yōu)橛?thisObj 指定的新對(duì)象。

  • 它們的不同之處:
    apply:
    最多只能有兩個(gè)參數(shù)——新this對(duì)象和一個(gè)數(shù)組 argArray。如果給該方法傳遞多個(gè)參數(shù),則把參數(shù)都寫進(jìn)這個(gè)數(shù)組里面,當(dāng)然,即使只有一個(gè)參數(shù),也要寫進(jìn)數(shù)組里面。如果 argArray 不是一個(gè)有效的數(shù)組或者不是 arguments 對(duì)象,那么將導(dǎo)致一個(gè) TypeError。如果沒有提供 argArray 和 thisObj 任何一個(gè)參數(shù),那么 Global 對(duì)象將被用作 thisObj,并且無法被傳遞任何參數(shù)。
    call:
    則是直接的參數(shù)列表,主要用在js對(duì)象各方法互相調(diào)用的時(shí)候,使當(dāng)前this實(shí)例指針保持一致,或在特殊情況下需要改變this指針。如果沒有提供 thisObj 參數(shù),那么 Global 對(duì)象被用作 thisObj。

更簡(jiǎn)單地說,apply和call功能一樣,只是傳入的參數(shù)列表形式不同:如 func.call(func1,var1,var2,var3) 對(duì)應(yīng)的apply寫法為:func.apply(func1,[var1,var2,var3])
也就是說:call調(diào)用的為單個(gè),apply調(diào)用的參數(shù)為數(shù)組

function sum(a,b){
    console.log(this === window);//true
    console.log(a + b);
 }
 sum(1,2);
 sum.call(null,1,2);
 sum.apply(null,[1,2]);

作用  

  • 調(diào)用函數(shù)
var info = 'tom';
function foo(){   
    //this指向window 
    var info = 'jerry';
    console.log(this.info);   //tom
    console.log(this===window)  //true
}
foo(); 
foo.call();
foo.apply();
  • call和apply可以改變函數(shù)中this的指向
var obj = {
        info:'spike'
}
foo.call(obj);    //這里foo函數(shù)里面的this就指向了obj
foo.apply(obj);
  • 借用別的對(duì)象的方法
    eg:求數(shù)組中的最大值
var arr = [123,34,5,23,3434,23];
//方法一
var arr1 = arr.sort(function(a,b){
    return b-a;
});
console.log(arr1[0]);
//方法二
var max = Math.max.apply(null,arr)   //借用別的對(duì)象的方法
console.log(max);

問題2: 以下代碼輸出什么?

var john = { 
  firstName: "John" 
}
function func() { 
alert(this.firstName + ": hi!")
}
john.sayHi = func
john.sayHi()  // John: hi!,this指向調(diào)用sayHi()的john對(duì)象

問題3: 下面代碼輸出什么,為什么

func() 

function func() { 
  alert(this)    //window,因?yàn)樵诤瘮?shù)被直接調(diào)用時(shí)this綁定到全局對(duì)象。在瀏覽器中,window 就是該全局對(duì)象
}

問題4: 下面代碼輸出什么

document.addEventListener('click', function(e){
    console.log(this);  //#document.
                        //在事件處理程序中this代表事件源DOM對(duì)象
    setTimeout(function(){
        console.log(this);  //window.
                            //setTimeout、setInterval這兩個(gè)方法執(zhí)行的函數(shù)this也是全局對(duì)象
    }, 200);
}, false);

問題5:下面代碼輸出什么,why

var john = { 
  firstName: "John" 
}

function func() { 
  alert( this.firstName )
}
func.call(john)    //John
                   //call(john)傳入了john這個(gè)執(zhí)行上下文,this指向john這個(gè)對(duì)象

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

var module= {
  bind: function(){
    $btn.on('click', function(){
      console.log(this) //this指$btn
      this.showMsg();
    })
  },
  
  showMsg: function(){
    console.log('饑人谷');
  }
}
//修改后:
var module= {
  bind: function(){
     var cur = this;  //將this代表的module存到cur
    $btn.on('click', function(){
      console.log(this) //$btn
      cur.showMsg(); //饑人谷
    })
  },
  
  showMsg: function(){
    console.log('饑人谷');
  }
}

原型鏈相關(guān)問題

問題7:有如下代碼,解釋Person、 prototype、__proto__、p、constructor之間的關(guān)聯(lián)。

function Person(name){
    this.name = name;
}
Person.prototype.sayName = function(){
    console.log('My name is :' + this.name);
}
var p = new Person("若愚")
p.sayName();
  • Person是構(gòu)造函數(shù),也是一個(gè)對(duì)象,這個(gè)對(duì)象里面存在一個(gè)prototype屬性,而構(gòu)造函數(shù)內(nèi)部定義了實(shí)例的屬性和方法,這些屬性和方法是屬于該類的所有實(shí)例的特征;
  • p是通過構(gòu)造函數(shù)Person構(gòu)造出來的實(shí)例,也是擁有__proto__屬性。所以p.__proto__ === Person.prototype;
  • prototype是構(gòu)造函數(shù)內(nèi)部的原型對(duì)象,所以擁有contructor和__proto__屬性,其中contructor屬性指向構(gòu)造函數(shù)Person,__proto__指向該對(duì)象的原型,即
Person.prototype.__proto__ === Object.prototype;
Person.prototype.constructor == Person

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

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


問題9:對(duì)String做擴(kuò)展,實(shí)現(xiàn)如下方式獲取字符串中頻率最高的字符

var str = 'ahbbccdeddddfg';
var ch = str.getMostOften();
console.log(ch); //d , 因?yàn)閐 出現(xiàn)了5次

代碼如下:

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

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

    return key;
}
//方法二:
String.prototype.getMostOften = function(){
    var arr = this.split("");
    var result = arr.reduce(function(allLetters,letter){
        if(allLetters[letter]){
            allLetters[letter]++
        }else{
            allLetters[letter] = 1
        }
    
        return allLetters;          
    },{});
  var max = 0,k;
        for(var key in result){
            if (result[key]>max){
                max = result[key];
                k = key
            }
        }
    return k;
}
var str = 'ahbbccdeddddfg';
var ch = str.getMostOften();
console.log(ch); //d 

問題10: instanceOf有什么作用??jī)?nèi)部邏輯是如何實(shí)現(xiàn)的?

  • instanceOf:判斷一個(gè)對(duì)象是否為另一個(gè)對(duì)象的實(shí)例
function instanceOf(obj,fn){
    var oldpro = obj.__proto__;
    while(oldpro){
    if(oldpro === fn.prototype){
        return true;
    }else{
        oldpro = oldpro.__proto__;
    }
    }
    return false;
}

繼承相關(guān)問題

問題11:繼承有什么作用?

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

問題12: 下面兩種寫法有什么區(qū)別?

//方法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);

區(qū)別:同樣都是創(chuàng)建printName方法,方法1的printName方法是在函數(shù)Person實(shí)例對(duì)象里的,方法2是在Person的prototype對(duì)象上的。當(dāng)再創(chuàng)建一個(gè)Person實(shí)例對(duì)象的時(shí)候,方法1又將會(huì)再創(chuàng)建一個(gè)printName方法,占用新的內(nèi)存,而方法2將一個(gè)公用的printName方法寫在原型上,當(dāng)對(duì)象要使用該方法只需到原型鏈里調(diào)用就可以了,達(dá)到節(jié)省內(nèi)存的效果。

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

  • 作用:創(chuàng)建一個(gè)擁有指定原型和若干個(gè)指定屬性的對(duì)象。
  • 兼容性:


  • 使用:
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()的使用場(chǎng)景
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有什么作用? 如何使用?

  • 作用:判斷一個(gè)對(duì)象是否包含自定義屬性而不是原型鏈上的屬性,是JavaScript中唯一一個(gè)處理屬性但是不查找原型鏈的函數(shù)
  • 語法:obj.hasOwnProperty(prop)(prop為要檢測(cè)的屬性名稱)
  • 使用(以上一題為例):
p1.hasOwnProperty('name');//true
p1.hasOwnProperty('sayName');//false
Male.prototype.hasOwnProperty('sayAge');//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;
}
  • 作用:在Male函數(shù)中,調(diào)用Person函數(shù),使Male函數(shù)能夠執(zhí)行Person上的初始化代碼,實(shí)現(xiàn)構(gòu)造函數(shù)繼承。

問題16: 補(bǔ)全代碼,實(shí)現(xiàn)繼承

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

Person.prototype.getName = function(){
    console.log(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;
Male.prototype.getAge = function(){
    console.log(this.name);
};

var ruoyu = new Male('若愚', '男', 27);
ruoyu.getName();//若愚
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容