this

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

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

function.prototype.apply()

函數實例的call方法,可以指定該函數內部this的指向姐浮,即函數執(zhí)行時所在的作用域谷遂,然后在所指定的作用域中,調用該函數

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

    上面代碼中卖鲤,在全局環(huán)境運行函數foo時肾扰,this指向全局環(huán)境;call方法可以改變this的指向扫尖,指定this指向對象obj白对,然后
    在對象obj的作用域中運行函數foo

    call方法的參數,應該是一個對象换怖。如果參數為空甩恼、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方法的參數是一個原始值条摸,那么這個原始值會自動轉成對應的包裝對象,然后傳入call方法

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

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

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

function.prototype.bind()

    bind方法用于將函數體內的this綁定到某個對象懦冰,然后返回一個新函數灶轰。

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

    上面代碼中,我們將d.getTime方法賦給變量print刷钢,然后調用print就報錯了笋颤。這是因為getTime方法內部的this,綁定
    Date對象的實例内地,當把getTime方法賦給變量print以后伴澄,在全部環(huán)境中調用print函數,內部的this已經不指向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內部的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這個變量

    上面代碼中航背,函數func是在全局環(huán)境中運行的喉悴,這時inc內部的this指向頂層對象window,所以counter.count是不會
    變的玖媚,反而創(chuàng)建了一個全局變量count箕肃。因為window.count原來等于undefined,進行遞增運算后undefined++就等于
    NaN.
    為了解決這個問題,可以使用bind方法今魔,將inc內部的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函數賦值給john.sayHi時,相當于給對象john添加了一個sayHi的
方法错森,當john調用這個方法時咏删,這個方法內部的this會指向john

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

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

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

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

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

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

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

var john = { 
  firstName: "John" 
}

function func() { 
  alert( this.firstName )
}
func.call(john)
輸出John,因為通過call方法辰狡,把函數func中的this指向對象john,所以會輸出John

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

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

不應該在事件綁定的函數中使用this指向Module宛篇,因為有事件綁定的回調
函數,它里面的this指向事件源薄湿,所以console.log(this)中的this指向事件源
$btn叫倍,this.showMsg()中的this也是指向$btn.

修改方法:
var module= {
  bind: function(){
    var _this = this//在this可以指向module的函數中先保存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可以這樣調用 p.toString()桥嗤。toString是哪里來的? 畫出原型圖?并解釋什么是原型鏈须妻。

對象p的原型鏈圖

當對對象p調用toString方法時,首先他會在自己本身中查找有沒有這個方法泛领,如果沒有荒吏,則沿著他的p.ptoto這個指針去查找他的構造函數的原型對象中有沒有,即Person.prototype有沒有渊鞋,沒有的話繼續(xù)順著Person.prototype.proto這個指針繼續(xù)向上查找绰更,也就是說只要存在proto這個指針,在對應的屬性和方法沒有查到之前篓像,查找不會停下动知,直到沒有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有什么作用奠滑?內部邏輯是如何實現(xiàn)的丹皱?

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

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

    function _instanceof(obj,func){
        if(obj.__proto__ === func.prototype){//先判斷該對象的直接原型
對象是否等于構造函數的prototype屬性,如果是宋税,返回true
            return true
        }else {//如果不是摊崭,把obj的原型鏈上升一層,繼續(xù)判斷它的原型
對象的原型對象是否等于某個構造函數的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);

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

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

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

    Object.create方法用于從原型對象生成新的實例對象厌杜,可以替代new
命令
    它接受一個對象作為參數,返回一個新對象计螺,后者完全繼承前者的屬
性夯尽,即原有對象成為新對象的原型。
    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函數把Person中的this指向Male半等,并傳入參數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杀饵,然后賦參數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();

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市谜悟,隨后出現(xiàn)的幾起案子话肖,更是在濱河造成了極大的恐慌,老刑警劉巖葡幸,帶你破解...
    沈念sama閱讀 222,807評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件最筒,死亡現(xiàn)場離奇詭異,居然都是意外死亡蔚叨,警方通過查閱死者的電腦和手機床蜘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,284評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蔑水,“玉大人邢锯,你說我怎么就攤上這事〔蟊穑” “怎么了丹擎?”我有些...
    開封第一講書人閱讀 169,589評論 0 363
  • 文/不壞的土叔 我叫張陵,是天一觀的道長领曼。 經常有香客問我鸥鹉,道長,這世上最難降的妖魔是什么庶骄? 我笑而不...
    開封第一講書人閱讀 60,188評論 1 300
  • 正文 為了忘掉前任毁渗,我火速辦了婚禮,結果婚禮上单刁,老公的妹妹穿的比我還像新娘灸异。我一直安慰自己府适,他們只是感情好,可當我...
    茶點故事閱讀 69,185評論 6 398
  • 文/花漫 我一把揭開白布肺樟。 她就那樣靜靜地躺著檐春,像睡著了一般。 火紅的嫁衣襯著肌膚如雪么伯。 梳的紋絲不亂的頭發(fā)上疟暖,一...
    開封第一講書人閱讀 52,785評論 1 314
  • 那天,我揣著相機與錄音田柔,去河邊找鬼俐巴。 笑死,一個胖子當著我的面吹牛硬爆,可吹牛的內容都是我干的欣舵。 我是一名探鬼主播,決...
    沈念sama閱讀 41,220評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼缀磕,長吁一口氣:“原來是場噩夢啊……” “哼缘圈!你這毒婦竟也來了?” 一聲冷哼從身側響起袜蚕,我...
    開封第一講書人閱讀 40,167評論 0 277
  • 序言:老撾萬榮一對情侶失蹤糟把,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后廷没,有當地人在樹林里發(fā)現(xiàn)了一具尸體糊饱,經...
    沈念sama閱讀 46,698評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,767評論 3 343
  • 正文 我和宋清朗相戀三年颠黎,在試婚紗的時候發(fā)現(xiàn)自己被綠了另锋。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,912評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡狭归,死狀恐怖夭坪,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情过椎,我是刑警寧澤室梅,帶...
    沈念sama閱讀 36,572評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站疚宇,受9級特大地震影響亡鼠,放射性物質發(fā)生泄漏。R本人自食惡果不足惜敷待,卻給世界環(huán)境...
    茶點故事閱讀 42,254評論 3 336
  • 文/蒙蒙 一间涵、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧榜揖,春花似錦勾哩、人聲如沸抗蠢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,746評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽迅矛。三九已至,卻和暖如春潜叛,著一層夾襖步出監(jiān)牢的瞬間秽褒,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,859評論 1 274
  • 我被黑心中介騙來泰國打工威兜, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留震嫉,地道東北人。 一個月前我還...
    沈念sama閱讀 49,359評論 3 379
  • 正文 我出身青樓牡属,卻偏偏與公主長得像,于是被迫代替她去往敵國和親扼睬。 傳聞我的和親對象是個殘疾皇子逮栅,可洞房花燭夜當晚...
    茶點故事閱讀 45,922評論 2 361

推薦閱讀更多精彩內容