this
問題1: apply、call 、bind有什么作用,什么區(qū)別
call 和 apply 都是為了改變某個(gè)函數(shù)運(yùn)行時(shí)的上下(context)而存在的,換句話說,就是為了改變函數(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ù)來調(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 三者都是用來改變函數(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)用 。
參考
問題2: 以下代碼輸出什么?
var john = {
firstName: "John"
}
function func() {
alert(this.firstName + ": hi!")
}
john.sayHi = func
john.sayHi() //輸出:John:hi!
問題3: 下面代碼輸出什么,為什么
func()
function func() {
alert(this)//輸出 [object window],因?yàn)樵诤瘮?shù)被直接調(diào)用時(shí)this綁定到全局對(duì)象,在瀏覽器中,window 就是該全局對(duì)象
}
問題4:下面代碼輸出什么
document.addEventListener('click', function(e){
console.log(this);//document
setTimeout(function(){
console.log(this);//window:setTimeout里的this指向window
}, 200);
}, false);
問題5:下面代碼輸出什么,為什么
var john = {
firstName: "John"
}
function func() {
alert( this.firstName )
}
func.call(john)//John因?yàn)閒unc.call(john)的this就是第一個(gè)參數(shù)john
問題6: 以下代碼有什么問題,如何修改
var module= {
bind: function(){
$btn.on('click', function(){
console.log(this) //this指$btn
this.showMsg();
})
},
showMsg: function(){
console.log('hunger');
}
}
問題
//在事件處理程序中this代表事件源DOM對(duì)象,所以該處的this指向$btn
//this.showMsg() 同理這里的this指向$btn,所以這里會(huì)出錯(cuò),因?yàn)?btn中沒有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)問題
問題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();
通過函數(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是哪里來

2.畫出原型圖

3.解釋原型鏈
首先來說說prototype屬性:不像每個(gè)對(duì)象都有proto屬性來標(biāo)識(shí)自己所繼承的原型,只有函數(shù)才有prototype屬性。
JS不像其它面向?qū)ο蟮恼Z言,它沒有類(class,ES6引進(jìn)了這個(gè)關(guān)鍵字)的概念。JS通過函數(shù)來模擬類。
當(dāng)你創(chuàng)建函數(shù)時(shí),JS會(huì)為這個(gè)函數(shù)自動(dòng)添加prototype屬性,值是空對(duì)象。而一旦你把這個(gè)函數(shù)當(dāng)作構(gòu)造函數(shù)(constructor)調(diào)用(即通過new關(guān)鍵字調(diào)用),那么JS就會(huì)幫你創(chuàng)建該構(gòu)造函數(shù)的實(shí)例,實(shí)例繼承構(gòu)造函數(shù)prototype的所有屬性和方法(實(shí)例通過設(shè)置自己的proto指向承構(gòu)造函數(shù)的prototype來實(shí)現(xiàn)這種繼承)。
JS正是通過proto和prototype的合作實(shí)現(xiàn)了原型鏈,以及對(duì)象的繼承。
構(gòu)造函數(shù),通過prototype來存儲(chǔ)要共享的屬性和方法,也可以設(shè)置prototype指向現(xiàn)存的對(duì)象來繼承該對(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)訪問一個(gè)對(duì)象的某個(gè)屬性時(shí),會(huì)先在這個(gè)對(duì)象本身屬性上查找,如果沒有找到,則會(huì)去它的proto隱式原型上查找,即它的構(gòu)造函數(shù)的prototype,如果還沒有找到就會(huì)再在構(gòu)造函數(shù)的prototype的proto中查找,這樣一層一層向上查找就會(huì)形成一個(gè)鏈?zhǔn)浇Y(jié)構(gòu),我們稱為原型鏈。
我們知道JS是單繼承的,Object.prototype是原型鏈的頂端,所有對(duì)象從它繼承了包括toString等等方法和屬性。
問題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á)式零次或多次

問題10: instanceOf有什么作用??jī)?nèi)部邏輯是如何實(shí)現(xiàn)的?
instanceof用于判斷某個(gè)變量是否是某個(gè)對(duì)象的實(shí)例,返回值為true或false
instanceof
通過探測(cè)obj.proto.proto... === Constructor.prototype來驗(yàn)證obj是否是Constructor的實(shí)例。
:對(duì)象的proto屬性,一直往下查proto屬性是不是等于構(gòu)造函數(shù)的prototype屬性
繼承相關(guān)問題
問題11:繼承有什么作用?
- 繼承是指一個(gè)對(duì)象直接使用另一對(duì)象的屬性和方法??梢蕴岣邚?fù)用性,省代碼
- 作用:繼承劃分了類的層次性,父類代表的是更一般、更泛化的類,而子類則是更為具體、更為細(xì)化
問題12: 下面兩種寫法有什么區(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 方法直接寫在函數(shù)Person中,當(dāng)創(chuàng)建Person的實(shí)例時(shí),每個(gè)實(shí)例都有自己的printName 方法方法二中:printName 方法是寫在Person.prototype中,當(dāng)創(chuàng)建Person的實(shí)例時(shí),每個(gè)實(shí)例中沒有自己的PrintName方法,當(dāng)實(shí)例調(diào)用PrintName時(shí),無法在自己體內(nèi)找到,所以會(huì)通過proto去原型里面找,也就是Person.prototype當(dāng)中去找。所以第二種方法中,PrintName是所有實(shí)例公用的。
- 作用
第二種在原型里面找方法:不用自己再開辟內(nèi)存空間去創(chuàng)建一個(gè)方法
問題13: Object.create 有什么作用?兼容性如何?
- 使用 Object.create 創(chuàng)建對(duì)象
ECMAScript 5 中引入了一個(gè)新方法:Object.create()可以調(diào)用這個(gè)方法來創(chuàng)建一個(gè)新對(duì)象。新對(duì)象的原型就是調(diào)用 create
方法時(shí)傳入的第一個(gè)參數(shù) -
兼容性
這是ES5才有的方法對(duì)于低版本瀏覽器兼容效果不理想
問題14: hasOwnProperty有什么作用? 如何使用?
- 檢測(cè)對(duì)象的屬性是定義在自身上還是在原型鏈上,有必要使用** [hasOwnProperty] **方法,所有繼承自 Object.proptotype 的對(duì)象都包含這個(gè)方法。會(huì)返回一個(gè)布爾值
[hasOwnProperty]是 JavaScript 中唯一一個(gè)只涉及對(duì)象自身屬性而不會(huì)遍歷原型鏈的方法。

問題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í)例可以訪問PersonPerson的屬性
this.age = age;
}
問題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();