this

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

在實際編程過程中,this的動態(tài)切換很容易讓人混淆它的指向,為了把this固定下來,避免意想不到的情況,javascript提供了apply,call,bind三種方法來切換/ 固定this的指向。

function.prototype.apply()

函數(shù)實例的call方法,可以指定該函數(shù)內(nèi)部this的指向,即函數(shù)執(zhí)行時所在的作用域,然后在所指定的作用域中,調(diào)用該函數(shù)

    var obj = {}
    function foo(){
        return this
    }
    foo() === this //true
    foo.call(obj) === obj //true

    上面代碼中,在全局環(huán)境運行函數(shù)foo時,this指向全局環(huán)境;call方法可以改變this的指向,指定this指向?qū)ο髈bj,然后
    在對象obj的作用域中運行函數(shù)foo

    call方法的參數(shù),應該是一個對象。如果參數(shù)為空、null和undefined,則默認傳入全局對象。

    var n = 123
    var obj = {n: 456}

    function a(){
        console.log(this.n)
    }

    a.call() // 123
    a.call(null)//123
    a.call(undefined)//123
    a.call(window)//123
    a.call(obj) // 456

    如果call方法的參數(shù)是一個原始值,那么這個原始值會自動轉(zhuǎn)成對應的包裝對象,然后傳入call方法

    var f = function(){
        return this
    }
    f.call(5)
    5是一個原始值,他的包裝對象為Number,相當于f.call(Number),返回Number{[[primitive]] : 5}
    call方法還可以接受多個參數(shù)。
    func.call(thisValue,arg1,arg2,...)
    call的第一個參數(shù)就是this所要指向的對象,后面的參數(shù)則是函數(shù)調(diào)用時所需的參數(shù)。
    function add(a,b){
        return a+b
    }
    add.call(this,1,2) // 3
    call方法的一個應用是調(diào)用對象的原生方法。

    var obj = {}
    obj.hasOwnProperty('toString')//false
    //覆蓋掉繼承的hasOwnProperty方法
    obj.hasOwnProperty = function(){
        return true
    }
    obj.hasOwnProperty('toString')//true,傳入任何參數(shù)都返回true
    Object.prototype.hasOwnproperty.call(obj,'toString') // false
function.prototype.apply()
    apply方法的作用與call類似,也是改變this的指向,然后再調(diào)用該函數(shù)。唯一的區(qū)別是,它接收一個數(shù)組作為函數(shù)執(zhí)行時
    的參數(shù),使用格式如下
    func.apply(thisValue,[arg1,arg2,...])

    利用這一點,可以做一些有用的應用。
    1. 找出數(shù)組最大元素
    javascript不提供找出數(shù)組最大元素的函數(shù)。結(jié)合使用apply方法和Math.max方法,就可以返回數(shù)組的最大元素.
    var a = [2,4,7,10,56]
    Math.max.apply(null,a)//56
    2.轉(zhuǎn)換類似數(shù)組的對象
    利用數(shù)組對象的slice方法,可以將一個類似數(shù)組的對象(比如arguments對象)轉(zhuǎn)為真正的數(shù)組。
    Array.prototype.slice.apply({0:1,length:1})//[1],類數(shù)組對象有個length的屬性
    Array.prototype.slice.apply({0:1})//[],沒有l(wèi)ength屬性,默認不被識別為類數(shù)組對象,返回空數(shù)組

function.prototype.bind()

    bind方法用于將函數(shù)體內(nèi)的this綁定到某個對象,然后返回一個新函數(shù)。

    var d = new Date()
    d.getTime() // 1491058448289
    var print = d.getTime
    print()

    上面代碼中,我們將d.getTime方法賦給變量print,然后調(diào)用print就報錯了。這是因為getTime方法內(nèi)部的this,綁定
    Date對象的實例,當把getTime方法賦給變量print以后,在全部環(huán)境中調(diào)用print函數(shù),內(nèi)部的this已經(jīng)不指向Date對象的實例了
    bind方法可以解決這個問題,讓log方法綁定console對象。

    var print = d.getTime.bind(d)
    print() //1491058927995

    下面是一個更清晰的例子

    var counter = {
        count: 0,
        inc: function(){
            this.count++
        }
    }
    counter.count // 0
    counter.inc()
    counter.count // 1
    上面代碼中,counter.inc內(nèi)部的this,默認指向counter對象,如果將這個方法賦值給另一個變量,就會報錯
    var counter = {
        count: 0,
        inc: function(){
            this.count++
        }
    }

    var func = counter.inc // 相當于 var func = function(){this.count++} 
    func()
    counter.count // 0
    count // NaN全局環(huán)境中并沒有count這個變量

    上面代碼中,函數(shù)func是在全局環(huán)境中運行的,這時inc內(nèi)部的this指向頂層對象window,所以counter.count是不會
    變的,反而創(chuàng)建了一個全局變量count。因為window.count原來等于undefined,進行遞增運算后undefined++就等于
    NaN.
    為了解決這個問題,可以使用bind方法,將inc內(nèi)部的this綁定到counter對象
    var func = counter.inc.bind(couonter)
    func()
    coounter.count // 1

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

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

輸出一個彈框,‘John:hi’
當把func函數(shù)賦值給john.sayHi時,相當于給對象john添加了一個sayHi的
方法,當john調(diào)用這個方法時,這個方法內(nèi)部的this會指向john

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

func() 
function func() { 
  alert(this)
}

輸出window對象,因為func調(diào)用時處在全局環(huán)境中,它內(nèi)部的this指向全局對象window

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

document.addEventListener('click', function(e){
    console.log(this);
    setTimeout(function(){
        console.log(this);
    }, 200);
}, false);

分別輸出document和window
綁定事件的函數(shù)中,this指向事件源
setTimeout中的this指向全局對象window

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

var john = { 
  firstName: "John" 
}

function func() { 
  alert( this.firstName )
}
func.call(john)
輸出John,因為通過call方法,把函數(shù)func中的this指向?qū)ο骿ohn,所以會輸出John

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

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

不應該在事件綁定的函數(shù)中使用this指向Module,因為有事件綁定的回調(diào)
函數(shù),它里面的this指向事件源,所以console.log(this)中的this指向事件源
$btn,this.showMsg()中的this也是指向$btn.

修改方法:
var module= {
  bind: function(){
    var _this = this//在this可以指向module的函數(shù)中先保存this
    $btn.on('click', function(){
      console.log(this) //this指什么
      _this.showMsg();
    })
  },
  
  showMsg: function(){
    console.log('饑人谷');
  }
}

原型鏈相關問題

問題7:有如下代碼,解釋Person、 prototype、proto、p、constructor之間的關聯(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();

關系圖

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

對象p的原型鏈圖

當對對象p調(diào)用toString方法時,首先他會在自己本身中查找有沒有這個方法,如果沒有,則沿著他的p.ptoto這個指針去查找他的構造函數(shù)的原型對象中有沒有,即Person.prototype有沒有,沒有的話繼續(xù)順著Person.prototype.proto這個指針繼續(xù)向上查找,也就是說只要存在proto這個指針,在對應的屬性和方法沒有查到之前,查找不會停下,直到?jīng)]有proto為止,也就是到達null為止。我們把這個由proto指針串起來的直到Object.prototype.proto為 null的鏈叫做原型鏈
原型鏈

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

    String.prototype.getMostOften = function(){
        var res,
            count = {},
            times = 0
            
        this.split('').forEach(function(item){
            if(count.hasOwnProperty(item)){
                count[item]++
            }else {
                count[item] = 1
            }
        })
        
        for(key in count){
            if(count[key]>times){
                times = count[key]
                res = key
            }
        }
        return res + '因為' + res + '出現(xiàn)了' + times + '次'
    }
var str = 'ahbbccdeddddfg';
var ch = str.getMostOften();
console.log(ch); //d , 因為d 出現(xiàn)了5次

問題10: instanceof有什么作用?內(nèi)部邏輯是如何實現(xiàn)的?

The instanceof operator tests whether an object has in its prototype chain the prototype property of a constructor.

instanceof運算符用來判斷一個對象的原型鏈中是否存在某個構造函數(shù)的原型對象

    function _instanceof(obj,func){
        if(obj.__proto__ === func.prototype){//先判斷該對象的直接原型
對象是否等于構造函數(shù)的prototype屬性,如果是,返回true
            return true
        }else {//如果不是,把obj的原型鏈上升一層,繼續(xù)判斷它的原型
對象的原型對象是否等于某個構造函數(shù)的prototype屬性,進行一個遞歸的判斷
            return _instanceof(obj.__proto__,func)
        }
    }

繼承相關問題

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

首先什么是繼承:繼承是指一個對象可以直接使用另一個對象的屬性和方法

繼承提高了代碼的可重用性,因為子類擁有了父類的屬性和方法,修改代碼時只需修改父類的屬性和方法,那么子類的也會隨之修改

說到繼承,不得不提多態(tài),多態(tài)是指針對同一個方法,子類之間可以有不同的表現(xiàn),也就是說子類可以重寫或者覆蓋父類的方法,但又不影響父類本身,也可以對子類本身原型對象進行一些屬性或方法的補充和擴展。

問題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);

第一種寫法把構造函數(shù)的所有屬性和方法都寫到了它本身,那么每次把該構造函數(shù)實例化為對象的時候,都會把所有的屬性和方法都執(zhí)行一遍,內(nèi)存中存儲了很多相同的方法

第二種寫法把構造函數(shù)的方法寫到了它的prototype屬性里,每次把該構造函數(shù)實例化的時候,方法存在了其原型對象中,相當于創(chuàng)建了一份公共代碼,節(jié)約了內(nèi)存,提高了性能

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

    Object.create方法用于從原型對象生成新的實例對象,可以替代new
命令
    它接受一個對象作為參數(shù),返回一個新對象,后者完全繼承前者的屬
性,即原有對象成為新對象的原型。
    var A = {
        print: function(){
            console.log('hello')
        }
    }
    var B = Object.create(A)
    B.print()//hello
    B.print === A.print // true
    上面代碼中,object.create方法在A的基礎上生成了B。此時,A就成
了B的原型,B就繼承了A的所有屬性和方法。這段代碼等同于下面的代碼

    var A = function(){}
    A.prototype.print = function(){
        console.log('hello')
    }
    var B = new A()
    B.print === A.prototype.print
    實際上,Object.create方法可以用下面的代碼代替。如果老師瀏覽器
不支持Object.create方法,就可以用這段代碼自己部署
Object.create 方法瀏覽器兼容性

問題14: hasOwnProperty有什么作用? 如何使用?

The hasOwnProperty() method returns a boolean indicating whether the object has the specified property as own (not inherited) property.

hasOwnProperty方法返回一個布爾值,判斷一個對象是否包含自定義屬性和方法,而不是原型鏈上的屬性和方法

    function C(name,age){
        this.name = name
        this.age = age

    }
    C.prototype.sayName = function(){
        console.log(this.name)
    }

    var d = new C('jack',10)
    d.hasOwnProperty('name') // true
    d.hasOwnProperty('sayName')//false

問題15:如下代碼中call的作用是什么?

function Person(name, sex){
    this.name = name;
    this.sex = sex;
}
function Male(name, sex, age){
    Person.call(this, name, sex);    //這里的call函數(shù)把Person中的this指向Male,并傳入?yún)?shù)name和sex
    this.age = age;
}

問題16: 補全代碼,實現(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)//引用Person方法,把Person中的this指向Male,然后賦參數(shù)name和sex
       this.age = age
    }

    Male.prototype = Object.create(Person.prototype)//以Person.prototype屬性為原型,創(chuàng)建一個新的對象,添加到Male.prototype
屬性里,相當于創(chuàng)建一個空對象,這個空對象的__proto__指向Person.prototype
    Male.prototype.constructor = Male//將Male的prototype屬性中的constructor改為他自己
    Male.prototype.getAge = function(){
        console.log(this.age)
    };

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

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,983評論 6 537
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,772評論 3 422
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,947評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,201評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,960評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,350評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,406評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,549評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,104評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,914評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,089評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,647評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,340評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,753評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,007評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,834評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,106評論 2 375

推薦閱讀更多精彩內(nèi)容