this 相關問題
apply、call 、bind有什么作用,什么區別?
- apply
語法格式:function.apply(this, [arguments])
參數this是在函數function運行時指定的this值,在調用function時可以為它指定一個this對象,this指的就是調用function的對象(函數執行時所在的上下文),然后在這個上下文中調用該函數,作用就是以對象的方法的形式來調用函數,如:
f.apply(o);
類似于
o.method=f; //f函數類似于o對象的臨時方法
o.method();//調用它
apply方法的作用和call方法類似,只有一個區別,call方法傳入的是參數列表,而apply方法傳入的是一個包含多個參數的數組。
如:
f.apply(o,[1,2]);
f.call(o,1,2);
bind的作用:
bind方法主要是將函數綁定到某個對象上,當在函數f()上調用bind方法并傳入一個對象o作為參數,這個方法將返回一個新的函數。調用新函數時,會把原始函數當做對象o的方法調用,傳入新函數的實參都會傳到原始函數,
function f(y){
return this.x+y;
}
var o={
x:1
}
var g=f.bind(o);//通過g(x)來調用o.f(x);
g(2) //3
bind方法將f函數內部的this綁定到o對象上,當調用f函數時,f函數會以創建它時傳入 bind()方法的第一個參數作為 this,傳入 bind() 方法的第二個以及以后的參數加上綁定函數運行時本身的參數按照順序作為原函數的參數來調用原函數。
三者比較:
apply 、 call 、bind 三者都是用來改變函數的this對象的指向的;
apply 、 call 、bind 三者第一個參數都是this要指向的對象,也就是想指定的執行上下文;
apply 、 call 、bind 三者都可以在this后傳參數;
bind 是返回新的函數,可以之后調用;apply 、call 則是立即調用 。
以下代碼輸出什么?
var john = {
firstName: "John"
}
function func() {
alert(this.firstName + ": hi!")
}
john.sayHi = func
john.sayHi() //John hi!
下面代碼輸出什么,為什么
func()
function func() {
alert(this)
}
//window,因為this指向的函數運行時的環境,現在func的執行上下文是window,所以輸出window.
下面代碼輸出什么
document.addEventListener('click', function(e){
console.log(this);
setTimeout(function(){
console.log(this);
}, 200);
}, false);
1.#document,因為click方法是在document的環境中被調用的,所以this指向document。
2.window對象,setTimeout函數是在click事件結束之后才執行的,所以它的執行環境是window,this指向的是window
下面代碼輸出什么,why
var john = {
firstName: "John"
}
function func() {
alert( this.firstName )
}
func.call(john) //John,因為call的第一個參數傳入的時調用func的上下文,所以func函數在john的執行上下文中,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.而在這個事件的執行上下文中沒有
showMsg()函數,所以調用的時候會提示showMsg()is not a function。
showMsg()在bind的作用域里,所以把指向bind的this保存到self中,在click事件中使用就不會報錯了。
原型鏈相關問題
有如下代碼,解釋Person、 prototype、proto、p、constructor之間的關聯
function Person(name){
this.name = name;
}
Person.prototype.sayName = function(){
console.log('My name is :' + this.name);
}
var p = new Person("若愚")
p.sayName();
如圖:
??Person是一個構造函數,也是一個對象,函數內部定義了name屬性,和自身帶有的prototype屬性,所有實例Person的實例都會生成這些屬性。
??p是構造函數Person的一個實例,所以p具有name的屬性。因為每個構造函數的實例都會有一個隱藏的屬性proto,指向構造函數的prototype屬性,所以p里的proto指向Person中的prototype。
??Person.prototype是Person的原型對象,里面定義了一個sayName,所以Person的實例都可以調用該方法。prototype對象有一個constructor屬性,默認指向prototype對象所在的構造函數,所以圖中的constructor就指向構造函數Person.因為原型對象也是對象,所以Person.prototype中的proto就指向Person.prototype的原型。
上例中,對對象 p可以這樣調用 p.toString()。toString是哪里來的? 畫出原型圖?并解釋什么是原型鏈。
對象p的proto指向的是構造函數Person的原型對象,Person的原型對象也是個對象,也有自己的原型對象,這個原型對象就指Object.prototype,Object.prototype就有toString()這個方法。當一個對象調用一個方法時,會先在內部屬性找,如果找不到,就到它的原型去找,如果還是找不到,就到原型的原型去找。如果直到最頂層的Object.prototype還是找不到,則返回undefined。
原型鏈:
對象的屬性和方法,有可能是定義在自身,也有可能是定義在它的原型對象。由于原型本身也是對象,又有自己的原型,所以形成了一條原型鏈。
對String做擴展,實現如下方式獲取字符串中頻率最高的字符
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 "出現最多的字是"+index+"次數是"+max;
}
var str = 'ahbbccdeddddfgg';
var ch = str.getMostOften();
console.log(ch);//出現最多的字是d次數是5
instanceOf有什么作用?內部邏輯是如何實現的?
instanceof運算符返回一個布爾值,判斷對象是否是某個構造函數的實例。
instanceof運算符的左邊是實例對象,右邊是構造函數。它會檢查右邊構建函數的原型對象,是否在左邊對象的原型鏈上:
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;
}
繼承相關問題
繼承有什么作用?
1.實現代碼復用,減少內存消耗。
2.可以覆蓋父類的屬性,可以實現代碼的擴展。
下面兩種寫法有什么區別?
//方法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是函數自身的屬性,每new一個Person的實例就會開辟一塊內存存儲printName函數,內存消耗較大。
第二種方法把printName作為Person.prototype屬性,Person的所有實例的proto都指向同一個原型對象,所有實例都共用這個方法,可以節約內存。
Object.create 有什么作用?兼容性如何?
Object.create()方法用于創建一個新的對象,其中傳入的參數是該對象的原型,
如:
var obj1={
x:1
}
var obj2=Object.create(obj1)//所以obj2就繼承了obj1的屬性x了
兼容性:
hasOwnProperty有什么作用? 如何使用?
對象hasOwnProperty()方法用于檢測給定的名字是否是對象自有的屬性,對于繼承的屬性它將返回false.
使用方法:
var o={
x:1
}
o.hasOwnProperty(“x”) //true,因為o對象有一個自有屬性x
o.hasOwnProperty(“y”) //false,因為o對象沒有自有屬性y
o.hasOwnProperty(“toString”) //false,因為toString是繼承屬性。
如下代碼中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;
}
函數實例的call方法,可以指定函數內部this的指向,并在所指定的作用域中,調用該函數。Person.call(this,name,age) 的 意思就是使用 Person構造函數的實例在this對象(也就是當前的執行上下文,Male的作用域)下執行,那么 Male就有了Person的所有屬性和方法,實現了繼承。
補全代碼,實現繼承
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();