this 相關(guān)問題
apply、call 、bind有什么作用,什么區(qū)別?
- apply
語法格式:function.apply(this, [arguments])
參數(shù)this是在函數(shù)function運(yùn)行時(shí)指定的this值,在調(diào)用function時(shí)可以為它指定一個(gè)this對(duì)象,this指的就是調(diào)用function的對(duì)象(函數(shù)執(zhí)行時(shí)所在的上下文),然后在這個(gè)上下文中調(diào)用該函數(shù),作用就是以對(duì)象的方法的形式來調(diào)用函數(shù),如:
f.apply(o);
類似于
o.method=f; //f函數(shù)類似于o對(duì)象的臨時(shí)方法
o.method();//調(diào)用它
apply方法的作用和call方法類似,只有一個(gè)區(qū)別,call方法傳入的是參數(shù)列表,而apply方法傳入的是一個(gè)包含多個(gè)參數(shù)的數(shù)組。
如:
f.apply(o,[1,2]);
f.call(o,1,2);
bind的作用:
bind方法主要是將函數(shù)綁定到某個(gè)對(duì)象上,當(dāng)在函數(shù)f()上調(diào)用bind方法并傳入一個(gè)對(duì)象o作為參數(shù),這個(gè)方法將返回一個(gè)新的函數(shù)。調(diào)用新函數(shù)時(shí),會(huì)把原始函數(shù)當(dāng)做對(duì)象o的方法調(diào)用,傳入新函數(shù)的實(shí)參都會(huì)傳到原始函數(shù),
function f(y){
return this.x+y;
}
var o={
x:1
}
var g=f.bind(o);//通過g(x)來調(diào)用o.f(x);
g(2) //3
bind方法將f函數(shù)內(nèi)部的this綁定到o對(duì)象上,當(dāng)調(diào)用f函數(shù)時(shí),f函數(shù)會(huì)以創(chuàng)建它時(shí)傳入 bind()方法的第一個(gè)參數(shù)作為 this,傳入 bind() 方法的第二個(gè)以及以后的參數(shù)加上綁定函數(shù)運(yùn)行時(shí)本身的參數(shù)按照順序作為原函數(shù)的參數(shù)來調(diào)用原函數(shù)。
三者比較:
apply 、 call 、bind 三者都是用來改變函數(shù)的this對(duì)象的指向的;
apply 、 call 、bind 三者第一個(gè)參數(shù)都是this要指向的對(duì)象,也就是想指定的執(zhí)行上下文;
apply 、 call 、bind 三者都可以在this后傳參數(shù);
bind 是返回新的函數(shù),可以之后調(diào)用;apply 、call 則是立即調(diào)用 。
以下代碼輸出什么?
var john = {
firstName: "John"
}
function func() {
alert(this.firstName + ": hi!")
}
john.sayHi = func
john.sayHi() //John hi!
下面代碼輸出什么,為什么
func()
function func() {
alert(this)
}
//window,因?yàn)閠his指向的函數(shù)運(yùn)行時(shí)的環(huán)境,現(xiàn)在func的執(zhí)行上下文是window,所以輸出window.
下面代碼輸出什么
document.addEventListener('click', function(e){
console.log(this);
setTimeout(function(){
console.log(this);
}, 200);
}, false);
1.#document,因?yàn)閏lick方法是在document的環(huán)境中被調(diào)用的,所以this指向document。
2.window對(duì)象,setTimeout函數(shù)是在click事件結(jié)束之后才執(zhí)行的,所以它的執(zhí)行環(huán)境是window,this指向的是window
下面代碼輸出什么,why
var john = {
firstName: "John"
}
function func() {
alert( this.firstName )
}
func.call(john) //John,因?yàn)閏all的第一個(gè)參數(shù)傳入的時(shí)調(diào)用func的上下文,所以func函數(shù)在john的執(zhí)行上下文中,this指的john.
以下代碼有什么問題,如何修改
var module= {
bind: function(){
$btn.on('click', function(){
console.log(this) //this指什么
this.showMsg();
})
},
showMsg: function(){
console.log('饑人谷');
}
}
改:
var module= {
bind: function(){
var self=this;
$('.btn').on('click', function(){
console.log(this) //this指什么,指的是btn,
self.showMsg(); //
})
},
showMsg: function(){
console.log('饑人谷');
}
}
module.bind();//饑人谷
在click事件中的this指的都是$btn.而在這個(gè)事件的執(zhí)行上下文中沒有
showMsg()函數(shù),所以調(diào)用的時(shí)候會(huì)提示showMsg()is not a function。
showMsg()在bind的作用域里,所以把指向bind的this保存到self中,在click事件中使用就不會(huì)報(bào)錯(cuò)了。
原型鏈相關(guān)問題
有如下代碼,解釋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è)構(gòu)造函數(shù),也是一個(gè)對(duì)象,函數(shù)內(nèi)部定義了name屬性,和自身帶有的prototype屬性,所有實(shí)例Person的實(shí)例都會(huì)生成這些屬性。
??p是構(gòu)造函數(shù)Person的一個(gè)實(shí)例,所以p具有name的屬性。因?yàn)槊總€(gè)構(gòu)造函數(shù)的實(shí)例都會(huì)有一個(gè)隱藏的屬性proto,指向構(gòu)造函數(shù)的prototype屬性,所以p里的proto指向Person中的prototype。
??Person.prototype是Person的原型對(duì)象,里面定義了一個(gè)sayName,所以Person的實(shí)例都可以調(diào)用該方法。prototype對(duì)象有一個(gè)constructor屬性,默認(rèn)指向prototype對(duì)象所在的構(gòu)造函數(shù),所以圖中的constructor就指向構(gòu)造函數(shù)Person.因?yàn)樵蛯?duì)象也是對(duì)象,所以Person.prototype中的proto就指向Person.prototype的原型。

上例中,對(duì)對(duì)象 p可以這樣調(diào)用 p.toString()。toString是哪里來的? 畫出原型圖?并解釋什么是原型鏈。
對(duì)象p的proto指向的是構(gòu)造函數(shù)Person的原型對(duì)象,Person的原型對(duì)象也是個(gè)對(duì)象,也有自己的原型對(duì)象,這個(gè)原型對(duì)象就指Object.prototype,Object.prototype就有toString()這個(gè)方法。當(dāng)一個(gè)對(duì)象調(diào)用一個(gè)方法時(shí),會(huì)先在內(nèi)部屬性找,如果找不到,就到它的原型去找,如果還是找不到,就到原型的原型去找。如果直到最頂層的Object.prototype還是找不到,則返回undefined。
原型鏈:
對(duì)象的屬性和方法,有可能是定義在自身,也有可能是定義在它的原型對(duì)象。由于原型本身也是對(duì)象,又有自己的原型,所以形成了一條原型鏈。

對(duì)String做擴(kuò)展,實(shí)現(xiàn)如下方式獲取字符串中頻率最高的字符
String.prototype.getMostOften=function(){
var obj={};
for(var i=0;i<this.length;i++){
if(obj[this[i]]){
obj[this[i]]++;
}else{
obj[this[i]]=1;
}
}
var index;
var max=0;
for(var key in obj){
if(obj[key]>max){
max=obj[key];
index=key;
}
}
return "出現(xiàn)最多的字是"+index+"次數(shù)是"+max;
}
var str = 'ahbbccdeddddfgg';
var ch = str.getMostOften();
console.log(ch);//出現(xiàn)最多的字是d次數(shù)是5
instanceOf有什么作用?內(nèi)部邏輯是如何實(shí)現(xiàn)的?
instanceof運(yùn)算符返回一個(gè)布爾值,判斷對(duì)象是否是某個(gè)構(gòu)造函數(shù)的實(shí)例。
instanceof運(yùn)算符的左邊是實(shí)例對(duì)象,右邊是構(gòu)造函數(shù)。它會(huì)檢查右邊構(gòu)建函數(shù)的原型對(duì)象,是否在左邊對(duì)象的原型鏈上:
obj instanceof cls
function _instanceof(obj, cls) {
var p = obj.__proto__, cp = cls.prototype;
while(p) {
if(p === cp) return true;
p = p.__proto__;
}
return false;
}
繼承相關(guān)問題
繼承有什么作用?
1.實(shí)現(xiàn)代碼復(fù)用,減少內(nèi)存消耗。
2.可以覆蓋父類的屬性,可以實(shí)現(xiàn)代碼的擴(kuò)展。
下面兩種寫法有什么區(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);
第一種方法中的printName是函數(shù)自身的屬性,每new一個(gè)Person的實(shí)例就會(huì)開辟一塊內(nèi)存存儲(chǔ)printName函數(shù),內(nèi)存消耗較大。
第二種方法把printName作為Person.prototype屬性,Person的所有實(shí)例的proto都指向同一個(gè)原型對(duì)象,所有實(shí)例都共用這個(gè)方法,可以節(jié)約內(nèi)存。
Object.create 有什么作用?兼容性如何?
Object.create()方法用于創(chuàng)建一個(gè)新的對(duì)象,其中傳入的參數(shù)是該對(duì)象的原型,
如:
var obj1={
x:1
}
var obj2=Object.create(obj1)//所以obj2就繼承了obj1的屬性x了
兼容性:

hasOwnProperty有什么作用? 如何使用?
對(duì)象hasOwnProperty()方法用于檢測給定的名字是否是對(duì)象自有的屬性,對(duì)于繼承的屬性它將返回false.
使用方法:
var o={
x:1
}
o.hasOwnProperty(“x”) //true,因?yàn)閛對(duì)象有一個(gè)自有屬性x
o.hasOwnProperty(“y”) //false,因?yàn)閛對(duì)象沒有自有屬性y
o.hasOwnProperty(“toString”) //false,因?yàn)閠oString是繼承屬性。
如下代碼中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;
}
函數(shù)實(shí)例的call方法,可以指定函數(shù)內(nèi)部this的指向,并在所指定的作用域中,調(diào)用該函數(shù)。Person.call(this,name,age) 的 意思就是使用 Person構(gòu)造函數(shù)的實(shí)例在this對(duì)象(也就是當(dāng)前的執(zhí)行上下文,Male的作用域)下執(zhí)行,那么 Male就有了Person的所有屬性和方法,實(shí)現(xiàn)了繼承。
補(bǔ)全代碼,實(shí)現(xiàn)繼承
function Person(name, sex){
this.name=name;
this.age=sex;
}
Person.prototype.getName = function(){
console.log(this.name)
};
function Male(name, sex, age){
Person.call(this,name,sex);
this.age=age;
}
Male.prototype.getAge = function(){
console.log(this.age);
};
Male.prototype=Object.create(Person.prototype);
var ruoyu = new Male('若愚', '男', 27);
ruoyu.getName();