this
問(wèn)題1: apply贯溅、call 、bind有什么作用,什么區(qū)別
call 和 apply 都是為了改變某個(gè)函數(shù)運(yùn)行時(shí)的上下(context)而存在的驮捍,換句話說(shuō),就是為了改變函數(shù)體內(nèi)部 this 的指向
第一個(gè)參數(shù)都是希望設(shè)置的this對(duì)象脚曾,不同之處在于call方法接收參數(shù)列表东且,而apply接收參數(shù)數(shù)組
func.call(this, arg1, arg2); func.apply(this, [arg1, arg2])
bind
bind()方法會(huì)創(chuàng)建一個(gè)新函數(shù),稱為綁定函數(shù)斟珊,當(dāng)調(diào)用這個(gè)綁定函數(shù)時(shí)苇倡,綁定函數(shù)會(huì)以創(chuàng)建它時(shí)傳入 bind()方法的第一個(gè)參數(shù)作為 this,傳入 bind() 方法的第二個(gè)以及以后的參數(shù)加上綁定函數(shù)運(yùn)行時(shí)本身的參數(shù)按照順序作為原函數(shù)的參數(shù)來(lái)調(diào)用原函數(shù)
var foo = {
bar : 1,
eventBind: function(){
var _this = this;
$('.someClass').on('click',function(event) {
/* Act on the event */
console.log(_this.bar); //1
});
}
}
區(qū)別是:當(dāng)你希望改變上下文環(huán)境之后并非立即執(zhí)行囤踩,而是回調(diào)執(zhí)行的時(shí)候旨椒,使用 bind() 方法。而 apply/call 則會(huì)立即執(zhí)行函數(shù)堵漱。
總結(jié)一下:
apply 综慎、 call 、bind 三者都是用來(lái)改變函數(shù)的this對(duì)象的指向的勤庐;
apply 示惊、 call 好港、bind 三者第一個(gè)參數(shù)都是this要指向的對(duì)象,也就是想指定的上下文米罚;
apply 钧汹、 call 、bind 三者都可以利用后續(xù)參數(shù)傳參录择;
bind 是返回對(duì)應(yīng)函數(shù)拔莱,便于稍后調(diào)用;apply 隘竭、call 則是立即調(diào)用 塘秦。
參考
問(wèn)題2: 以下代碼輸出什么?
var john = {
firstName: "John"
}
function func() {
alert(this.firstName + ": hi!")
}
john.sayHi = func
john.sayHi() //輸出:John:hi!
問(wèn)題3: 下面代碼輸出什么,為什么
func()
function func() {
alert(this)//輸出 [object window],因?yàn)樵诤瘮?shù)被直接調(diào)用時(shí)this綁定到全局對(duì)象,在瀏覽器中动看,window 就是該全局對(duì)象
}
問(wèn)題4:下面代碼輸出什么
document.addEventListener('click', function(e){
console.log(this);//document
setTimeout(function(){
console.log(this);//window:setTimeout里的this指向window
}, 200);
}, false);
問(wèn)題5:下面代碼輸出什么,為什么
var john = {
firstName: "John"
}
function func() {
alert( this.firstName )
}
func.call(john)//John因?yàn)閒unc.call(john)的this就是第一個(gè)參數(shù)john
問(wèn)題6: 以下代碼有什么問(wèn)題尊剔,如何修改
var module= {
bind: function(){
$btn.on('click', function(){
console.log(this) //this指$btn
this.showMsg();
})
},
showMsg: function(){
console.log('hunger');
}
}
問(wèn)題
//在事件處理程序中this代表事件源DOM對(duì)象,所以該處的this指向$btn
//this.showMsg() 同理這里的this指向$btn,所以這里會(huì)出錯(cuò)菱皆,因?yàn)?btn中沒(méi)有showMsg()方法應(yīng)該為如下
修改后:
var module= {
bind: function(){
var that = this;//引用this
$btn.on('click', function(){
console.log(that)
that.showMsg();//this為module
})
},
showMsg: function(){
console.log('hunger');
}
}
原型鏈相關(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();
通過(guò)函數(shù)定義類Person历造,類自動(dòng)獲得屬性prototype,p是Person類的實(shí)例船庇,有一個(gè)內(nèi)部屬性_proto_,
他指向類的prototype吭产,p._proto_.constructor指向構(gòu)造函數(shù)Person。
8.上例中
1.對(duì)象 p可以這樣調(diào)用p.toString(),toString是哪里來(lái)
2.畫(huà)出原型圖
3.解釋原型鏈
首先來(lái)說(shuō)說(shuō)prototype屬性:不像每個(gè)對(duì)象都有proto屬性來(lái)標(biāo)識(shí)自己所繼承的原型鸭轮,只有函數(shù)才有prototype屬性臣淤。
JS不像其它面向?qū)ο蟮恼Z(yǔ)言,它沒(méi)有類(class窃爷,ES6引進(jìn)了這個(gè)關(guān)鍵字)的概念邑蒋。JS通過(guò)函數(shù)來(lái)模擬類。
當(dāng)你創(chuàng)建函數(shù)時(shí)按厘,JS會(huì)為這個(gè)函數(shù)自動(dòng)添加prototype屬性医吊,值是空對(duì)象。而一旦你把這個(gè)函數(shù)當(dāng)作構(gòu)造函數(shù)(constructor)調(diào)用(即通過(guò)new關(guān)鍵字調(diào)用)逮京,那么JS就會(huì)幫你創(chuàng)建該構(gòu)造函數(shù)的實(shí)例卿堂,實(shí)例繼承構(gòu)造函數(shù)prototype的所有屬性和方法(實(shí)例通過(guò)設(shè)置自己的proto指向承構(gòu)造函數(shù)的prototype來(lái)實(shí)現(xiàn)這種繼承)。
JS正是通過(guò)proto和prototype的合作實(shí)現(xiàn)了原型鏈,以及對(duì)象的繼承草描。
構(gòu)造函數(shù)览绿,通過(guò)prototype來(lái)存儲(chǔ)要共享的屬性和方法,也可以設(shè)置prototype指向現(xiàn)存的對(duì)象來(lái)繼承該對(duì)象穗慕。
對(duì)象的proto指向自己構(gòu)造函數(shù)的prototype饿敲。obj.proto.proto...的原型鏈由此產(chǎn)生
two = new Object()中Object是構(gòu)造函數(shù),所以two.proto就是Object.prototype逛绵。ES規(guī)范定義對(duì)象字面量的原型就是Object.prototype诀蓉。
當(dāng)訪問(wèn)一個(gè)對(duì)象的某個(gè)屬性時(shí),會(huì)先在這個(gè)對(duì)象本身屬性上查找暑脆,如果沒(méi)有找到,則會(huì)去它的proto隱式原型上查找狐肢,即它的構(gòu)造函數(shù)的prototype添吗,如果還沒(méi)有找到就會(huì)再在構(gòu)造函數(shù)的prototype的proto中查找,這樣一層一層向上查找就會(huì)形成一個(gè)鏈?zhǔn)浇Y(jié)構(gòu)份名,我們稱為原型鏈碟联。
我們知道JS是單繼承的,Object.prototype是原型鏈的頂端僵腺,所有對(duì)象從它繼承了包括toString等等方法和屬性鲤孵。
問(wèn)題9:對(duì)String做擴(kuò)展,實(shí)現(xiàn)如下方式獲取字符串中頻率最高的字符
法1:遍歷
String.prototype.getMostOften = function(){
var arr = [];
for(var i=0;i<this.length;i++){
if(arr[this[i]]){
++arr[this[i]];
}else{
arr[this[i]] = 1;//必須在這里賦值為1
}
}
var count = 0;
var maxKey;
for(var key in arr){
if(arr[key]>count){
count = arr[key];//數(shù)字
maxKey = key;//a,b..
}
}
var maxCount = count;
return maxKey+':因?yàn)?+maxKey+' 出現(xiàn)了'+maxCount+'次';
}
var str = 'ahbbccdeddddfg';
var ch = str.getMostOften();
console.log(ch); //d , 因?yàn)閐 出現(xiàn)了5次
法2:正則
String.prototype.getMostOften= function(str){
return str.split('').sort().join('').match(/(\S)\1*/g).sort(function(a,b){
return b.length - a.length;
})[0][0];
};
var str = 'ahbbccdeddddfg';
var ch = str.getMostOften(str);
var length = str.split('').sort().join('').match(/(\S)\1*/g).sort(function(a,b){
return b.length - a.length;
})[0].length;
console.log(ch+':因?yàn)?+ch+'出現(xiàn)了'+length+'次'); //d , 因?yàn)閐 出現(xiàn)了5次
sort() 方法用于對(duì)數(shù)組的元素進(jìn)行排序,是按照字符編碼的順序進(jìn)行排序
\S 匹配任何非空白字符
\1 指定第一個(gè)子匹配項(xiàng)
* 匹配前面的子表達(dá)式零次或多次
問(wèn)題10: instanceOf有什么作用辰如??jī)?nèi)部邏輯是如何實(shí)現(xiàn)的普监?
instanceof用于判斷某個(gè)變量是否是某個(gè)對(duì)象的實(shí)例,返回值為true或false
instanceof
通過(guò)探測(cè)obj.proto.proto... === Constructor.prototype來(lái)驗(yàn)證obj是否是Constructor的實(shí)例琉兜。
:對(duì)象的proto屬性,一直往下查proto屬性是不是等于構(gòu)造函數(shù)的prototype屬性
繼承相關(guān)問(wèn)題
問(wèn)題11:繼承有什么作用?
- 繼承是指一個(gè)對(duì)象直接使用另一對(duì)象的屬性和方法凯正。可以提高復(fù)用性,省代碼
- 作用:繼承劃分了類的層次性豌蟋,父類代表的是更一般廊散、更泛化的類,而子類則是更為具體梧疲、更為細(xì)化
問(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('hunger', 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 方法直接寫(xiě)在函數(shù)Person中允睹,當(dāng)創(chuàng)建Person的實(shí)例時(shí),每個(gè)實(shí)例都有自己的printName 方法方法二中:printName 方法是寫(xiě)在Person.prototype中幌氮,當(dāng)創(chuàng)建Person的實(shí)例時(shí)缭受,每個(gè)實(shí)例中沒(méi)有自己的PrintName方法,當(dāng)實(shí)例調(diào)用PrintName時(shí)浩销,無(wú)法在自己體內(nèi)找到贯涎,所以會(huì)通過(guò)proto去原型里面找,也就是Person.prototype當(dāng)中去找慢洋。所以第二種方法中塘雳,PrintName是所有實(shí)例公用的陆盘。
- 作用
第二種在原型里面找方法:不用自己再開(kāi)辟內(nèi)存空間去創(chuàng)建一個(gè)方法
問(wèn)題13: Object.create 有什么作用?兼容性如何败明?
- 使用 Object.create 創(chuàng)建對(duì)象
ECMAScript 5 中引入了一個(gè)新方法:Object.create()可以調(diào)用這個(gè)方法來(lái)創(chuàng)建一個(gè)新對(duì)象隘马。新對(duì)象的原型就是調(diào)用 create
方法時(shí)傳入的第一個(gè)參數(shù) -
兼容性
這是ES5才有的方法對(duì)于低版本瀏覽器兼容效果不理想
問(wèn)題14: hasOwnProperty有什么作用? 如何使用妻顶?
- 檢測(cè)對(duì)象的屬性是定義在自身上還是在原型鏈上酸员,有必要使用** [hasOwnProperty] **方法,所有繼承自 Object.proptotype 的對(duì)象都包含這個(gè)方法讳嘱。會(huì)返回一個(gè)布爾值
[hasOwnProperty]是 JavaScript 中唯一一個(gè)只涉及對(duì)象自身屬性而不會(huì)遍歷原型鏈的方法幔嗦。
問(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作用:改變作用域,可以引用構(gòu)造函數(shù),使Male實(shí)例可以訪問(wèn)PersonPerson的屬性
this.age = age;
}
問(wèn)題16: 補(bǔ)全代碼,實(shí)現(xiàn)繼承
function Person(name, sex){
this.name = name;
this.sex = sex;
}
Person.prototype.getName = function(){
console.log(this.name)
console.log(this.age)
console.log(this.sex)
};
function Male(name, sex, age){
Person.call(this,name,sex);
this.age = age;
}
Male.prototype=Object.create(Person.prototype)
//or
// var Temp = function(){}
// Temp.prototype = Person.prototype;
// Male.prototype = new Temp();
// Male.prototype.construction = Male;
Male.prototype.getAge = function(){
console.log(this.age)
};
var ruoyu = new Male('若愚', '男', 27);
ruoyu.getName();