this 相關(guān)問(wèn)題
問(wèn)題1: apply、call 养泡、bind有什么作用嗜湃,什么區(qū)別
- Function.prototype.bind:
bind奈应,返回一個(gè)新函數(shù),并且使函數(shù)內(nèi)部的this為傳入的第一個(gè)參數(shù)
var fn3 = obj1.fn.bind(obj1);
fn3();
- 使用call和apply設(shè)置this
call apply购披,調(diào)用一個(gè)函數(shù)杖挣,傳入函數(shù)執(zhí)行上下文及參數(shù)
fn.call(context, param1, param2...)
fn.apply(context, paramArray)
語(yǔ)法很簡(jiǎn)單,第一個(gè)參數(shù)都是希望設(shè)置的this對(duì)象刚陡,不同之處在于call方法接收參數(shù)列表惩妇,而apply接收參數(shù)數(shù)組
fn2.call(obj1);
fn2.apply(obj1);
它們的不同之處:
-
apply:
最多只能有兩個(gè)參數(shù)——新this對(duì)象和一個(gè)數(shù)組 argArray。如果給該方法傳遞多個(gè)參數(shù)橘荠,則把參數(shù)都寫(xiě)進(jìn)這個(gè)數(shù)組里面屿附,當(dāng)然郎逃,即使只有一個(gè)參數(shù)哥童,也要寫(xiě)進(jìn)數(shù)組里面。如果 argArray 不是一個(gè)有效的數(shù)組或者不是 arguments 對(duì)象褒翰,那么將導(dǎo)致一個(gè) TypeError贮懈。如果沒(méi)有提供 argArray 和 thisObj 任何一個(gè)參數(shù),那么 Global 對(duì)象將被用作 thisObj优训,并且無(wú)法被傳遞任何參數(shù)朵你。
-
call:
則是直接的參數(shù)列表,主要用在js對(duì)象各方法互相調(diào)用的時(shí)候揣非,使當(dāng)前this實(shí)例指針保持一致,或在特殊情況下需要改變this指針抡医。如果沒(méi)有提供 thisObj 參數(shù),那么 Global 對(duì)象被用作 thisObj早敬。
更簡(jiǎn)單地說(shuō)忌傻,apply和call功能一樣,只是傳入的參數(shù)列表形式不同:如 func.call(func1,var1,var2,var3) 對(duì)應(yīng)的apply寫(xiě)法為:func.apply(func1,[var1,var2,var3])
也就是說(shuō):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);
fn.call(context, param1, param2...)
fn.apply(context, paramArray)
問(wèn)題2: 以下代碼輸出什么?
var john = {
firstName: "John"
}
function func() {
alert(this.firstName + ": hi!")
}
john.sayHi = func
john.sayHi()
//輸出結(jié)果:join:hi水孩!
//此時(shí),this是join對(duì)象琐驴;
問(wèn)題3: 下面代碼輸出什么俘种,為什么
func()
function func() {
alert(this)
}
//輸出: Window
//原因:func()等價(jià)于func.call(undefined);
//而undefined會(huì)被瀏覽器默認(rèn)為全局對(duì)象window;
問(wèn)題4:下面代碼輸出什么
document.addEventListener('click', function(e){
console.log(this);
setTimeout(function(){
console.log(this);
}, 200);
}, false);
//輸出為:#document; window;
//在事件處理程序中this代表事件源DOM對(duì)象
//(setTimeout、setInterval這兩個(gè)方法執(zhí)行的函數(shù)this也是全局對(duì)象)
問(wèn)題5:下面代碼輸出什么绝淡,why
var john = {
firstName: "John"
}
function func() {
alert( this.firstName )
}
func.call(john)
//輸出: john
//解釋:call()中第一個(gè)參數(shù)表示定義的this值宙刘,即func()中的this代表join。
問(wèn)題6: 以下代碼有什么問(wèn)題牢酵,如何修改
var module= {
bind: function(){
$btn.on('click', function(){
console.log(this) //this指悬包?
this.showMsg();
})
},
showMsg: function(){
console.log('饑人谷');
}
}
//this指什么$btn
修改后
var module= {
bind: function(){
var _this = this;
$btn.on('click', function(){
console.log(_this) //_this指的是module;
_this.showMsg();//饑人谷
})
},
showMsg: function(){
console.log('饑人谷');
}
}
原型鏈相關(guān)問(wèn)題
問(wè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();
![](https://github.com/mhy-web/HomeWorks/tree/master/%E9%AB%98%E7%BA%A7/task2/images/prototype-0.png)
我們通過(guò)函數(shù)定義了類
Person
,類(函數(shù))自動(dòng)獲得屬性prototype;每個(gè)類的實(shí)例都會(huì)有一個(gè)內(nèi)部屬性
__proto__
季蚂,指向類的prototype屬性p
是構(gòu)造函數(shù)Person
的一個(gè)實(shí)例茫船,p
的__proto__
指向了Person的prototype屬性,prototype
是構(gòu)造函數(shù)內(nèi)部的原型對(duì)象扭屁,所以擁有contructor
和__proto__
屬性算谈,其中contructor
屬性指向構(gòu)造函數(shù)Person
,__proto__
指向該對(duì)象的原型.
問(wèn)題8: 上例中料滥,對(duì)對(duì)象 p可以這樣調(diào)用 p.toString()然眼。toString是哪里來(lái)的? 畫(huà)出原型圖?并解釋什么是原型鏈。
p.toString()方法是繼承構(gòu)造函數(shù)Object的原型對(duì)象里定義的toString方法葵腹,首先p會(huì)找自己的toString方法高每,如果沒(méi)有找到,
會(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è)就是原型鏈瘤缩。
在訪問(wèn)對(duì)象的屬性時(shí),如果在對(duì)象本身中沒(méi)有找到伦泥,則會(huì)去原型鏈中查找剥啤,如果找到,直接返回值不脯,如果整個(gè)鏈都遍歷且沒(méi)有找到
屬性府怯,則返回undefined。原型鏈一般實(shí)現(xiàn)為一個(gè)鏈表防楷,這樣就可以按照一定的順序來(lái)查找牺丙。
![](https://github.com/mhy-web/HomeWorks/tree/master/%E9%AB%98%E7%BA%A7/task2/images/prototype.png)
問(wèn)題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
問(wèn)題10: instanceOf有什么作用??jī)?nèi)部邏輯是如何實(shí)現(xiàn)的冲簿?
- instanceOf:判斷一個(gè)對(duì)象是否為另一個(gè)對(duì)象的實(shí)例
function isInstanceOf(obj,fn){
var oldProto = obj.__proto__;
do{
if(oldProto === fn.prototype){ //prototype是小寫(xiě)的粟判!
return true;
}else{
oldProto = oldProto.__proto__;
}
}while(oldProto){
return false;
}
}
繼承相關(guān)問(wèn)題
問(wèn)題11:繼承有什么作用?
繼承是指一個(gè)對(duì)象直接使用另一對(duì)象的屬性和方法。
JavaScript 對(duì)象有一個(gè)指向一個(gè)原型對(duì)象的鏈峦剔。當(dāng)試圖訪問(wèn)一個(gè)對(duì)象的屬性時(shí)档礁,它不僅僅在該對(duì)象上搜尋,還會(huì)搜尋該對(duì)象的原型吝沫,
以及該對(duì)象的原型的原型呻澜,依此層層向上搜索,直到找到一個(gè)名字匹配的屬性或到達(dá)原型鏈的末尾惨险。這就意味著羹幸,JS對(duì)象可以使用所有
其原型的所有方法,如果我們?cè)谠蜕咸砑有碌姆椒ū栌洌敲磳?shí)例也會(huì)擁有該方法栅受,能夠大大減少冗余代碼。
問(wèn)題12: 下面兩種寫(xiě)法有什么區(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ū)別:
方法一是將printName作為構(gòu)造函數(shù)的方法一屋,實(shí)例在進(jìn)行調(diào)用的時(shí)候是調(diào)用的自身的方法窘疮,較為消耗內(nèi)存。
方法二是將printName作為構(gòu)造函數(shù)原型的方法冀墨,所有實(shí)例共享這個(gè)方法。
問(wèn)題13: Object.create 有什么作用涛贯?兼容性如何诽嘉?
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
兼容性:
![](https://github.com/mhy-web/HomeWorks/tree/master/%E9%AB%98%E7%BA%A7/task2/images/%E5%85%BC%E5%AE%B9%E6%80%A7.jpg)
問(wèn)題14: hasOwnProperty有什么作用弟翘? 如何使用虫腋?
hasOwnPerperty是Object.prototype的一個(gè)方法,可以判斷一個(gè)對(duì)象是否包含自定義屬性而不是原型鏈上的屬性稀余,
hasOwnProperty是JavaScript中唯一一個(gè)處理屬性但是不查找原型鏈的函數(shù)
m.hasOwnProperty('name'); // true
m.hasOwnProperty('printName'); // false
Male.prototype.hasOwnProperty('printAge'); // true
問(wèn)題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;
}
問(wèn)題16: 補(bǔ)全代碼悦冀,實(shí)現(xiàn)繼承
function Person(name, sex){
// todo ...
this.name = name;
this.sex = sex;
}
Person.prototype.getName = function(){
// todo ...
console.log(this.name);
};
function Male(name, sex, age){
//todo ...
Person.call(this,name, sex);
this.age = age;
}
//todo ...
Male.prototype = Object.create(Person.prototype);
Male.prototype.constructor = Male;
Male.prototype.getAge = function(){
//todo ...
console.log(this.age);
};
var ruoyu = new Male('若愚', '男', 27);
ruoyu.printName();//若愚