1.以下代碼輸出什么?
var john = {
firstName: "John"
}
function func() {
alert(this.firstName + ": hi!")
}
john.sayHi = func
john.sayHi()//John:hi!
輸出John:hi!。解析:john.sayHi()
可理解為john.sayHi.call(john)
,即this指向john荐类,輸出即為John.firstName + ":hi!"
。
2.以下代碼輸出什么茁帽?
func()
function func() {
alert(this)
}
輸出window對象玉罐。func()
相當于func.call(undefined)
,故輸出window對象潘拨。若要改變this指向吊输,則應寫成:func.call(obj)
3.下面代碼輸出什么?
document.addEventListener('click', function(e){
console.log(this);
setTimeout(function(){
console.log(this);
}, 200);
}, false);
單擊頁面铁追,依次輸出document對象季蚂、window對象。
DOM對象綁定事件時,傳入的函數(shù)中的this綁定到該DOM對象
setTImeout 和 setInterval 這兩個方法執(zhí)行的函數(shù)中的this綁定到全局對象window扭屁。
4.以下代碼有什么問題算谈,如何修改
var module= {
bind: function(){
$btn.on('click', function(){
console.log(this) //this指$btn
this.showMsg();
})
},
showMsg: function(){
console.log('饑人谷');
}
}
在事件監(jiān)聽函數(shù)中 this.showMsg(), this指代 $btn 這個jQuery對象料滥,并不代表module對象然眼,因此 this.showMsg() 相當于 $btn.showMsg()。
想要在事件監(jiān)聽函數(shù)中 調用module 的方法葵腹,可以人為把this綁定到module對象高每,使用 bind() 即可:
var module= {
bind: function(){
$btn.on('click', function(){
console.log(this) //this指向module
this.showMsg();
}.bind(this))
},
showMsg: function(){
console.log('饑人谷');
}
}
也可以將module的this保存起來為that,最后用that.showMsg()
去執(zhí)行践宴。
也可以用ES6的箭頭函數(shù)鲸匿。
5.有如下代碼,解釋Person浴井、 prototype、proto霉撵、p磺浙、constructor之間的關聯(lián)
function Person(name){
this.name = name;
}
Person.prototype.sayName = function(){
console.log('My name is :' + this.name);
}
var p = new Person("Li")
p.sayName();
- 首先,
Person
是一個構造函數(shù)徒坡,而p
是它的一個實例撕氧。 - 故,
p.__proto__ == Person.prototype
喇完。 -
prototype
對象有一個constructor
屬性伦泥,指向prototype
對象所在的構造函數(shù)。故Person.prototype.constructor
指向Person锦溪,p.__proto__.constructor
也指向Person
不脯。
6.上例中,對對象 p可以這樣調用 p.toString()刻诊。toString是哪里來的? 畫出原型圖?并解釋什么是原型鏈防楷。
如圖所示,p自身沒有toString则涯,就到Person類的prototype去找复局,也沒有,prototype是個對象粟判,由Object類創(chuàng)建亿昏,但是仍然沒有toString,所以繼續(xù)到prototype的_ proto _ 也就是Object的prototype中去找档礁,最終找到了toString方法角钩。
由此引出原型鏈的概念:
每個對象都有一個proto屬性,其指向該對象的原型對象,而原型對象也是對象彤断,所以也有一個proto指向原型對象的原型對象野舶,這樣就組成了一條鏈,稱為原型鏈宰衙。在訪問對象的屬性時平道,如果在對象本身中沒有找到,則會去原型鏈中查找供炼,如果找到一屋,直接返回值。
原型鏈是實現(xiàn)繼承的主要方法袋哼。
7.對String做擴展冀墨,實現(xiàn)如下方式獲取字符串中頻率最高的字符
var str = 'ahbbccdeddddfg';
var ch = str.getMostOften();
console.log(ch); //d , 因為d 出現(xiàn)了5次
代碼如下:
String.prototype.getMostOften = function(){
var obj = {};
var max = 0;
var result;
for(var i=0; i<this.length; i++){
if(obj[str[i]]){
obj[str[i]] += 1;
} else {
obj[str[i]] = 1;
}
}
for(var key in obj){
if(obj[key]>max){
max = obj[key];
result = key;
}
}
return result;
};
8.instanceOf有什么作用?內部邏輯是如何實現(xiàn)的涛贯?
instanceOf運算符可以判斷一個對象是否是某個類的實例诽嘉。
如果一個對象通過沿著 _ proto _ 組成的原形鏈一層層查找其constructor屬性,如果有一層proto等于某類的prototype弟翘,則該對象是某類型的實例虫腋。
function instance(obj,fun){
if(obj.__proto__){
if(obj.__proto__ === fun.prototype){
return true;
} else {
return instance(obj.__proto__,fun);
}
}
return false;
}
console.log(instance([],Array)); //true
console.log(instance([],Object)); //true
console.log(instance([],String)); //false
9.繼承有什么用?
繼承是指一個對象直接使用另一對象的屬性和方法稀余。
繼承機制使得不同的實例可以共享構造函數(shù)的原型對象的屬性和方法悦冀,提高了代碼的復用性。
10. 下面兩種寫法有什么區(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ù)上师骗,而后者將方法寫在構造函數(shù)的prototype對象上历等,前者在每生成一個實例之后實例的printName就占用內存,而后者每生成一個實例后會共享構造函數(shù)prototype對象上的printName方法辟癌,以達到節(jié)省內存的效果募闲,也便于后期維護。
11.Object.create 有什么作用愿待?兼容性如何浩螺?
- 該方法接受一個對象作為參數(shù),然后以它為原型仍侥,返回一個實例對象要出。該實例完全繼承原型對象的屬性。還可傳入第二個參數(shù)农渊,該參數(shù)是一個屬性描述對象患蹂,它所描述的對象屬性或颊,會添加到實例對象,作為該對象自身的屬性传于。
- Object.create是ES5中的方法囱挑,各大瀏覽器的最新版本(包括IE9)都部署了這個方法。如果老式瀏覽器不支持Object.create方法沼溜,可以就用這段代碼自己部署平挑。
if(typeof Object.create !== 'function'){
Object.create = function(obj){
function F(){}
F.prototype = obj;
return new F();
};
}
以上代碼說明,Object.create
方法的實質是新建一個構造函數(shù)F
系草,使其prototype屬性指向參數(shù)對象obj
通熄,最后返回一個F
的實例,從而讓該實例繼承obj
對象的屬性。
12.hasOwnProperty有什么作用找都? 如何使用唇辨?
hasOwnProperty
方法用于返回一個布爾值,用于判斷某個屬性定義在對象自身能耻,還是定義在原型鏈上赏枚。
function Person(name, sex){
this.name = name;
this.sex = sex;
}
Person.prototype.printName = function(){
console.log(this.name);
}
var p1 = new Person('Li', 23)
p1.hasOwnProperty('name') //true
p1.hasOwnProperty('printName') //false
13.如下代碼中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的作用是,指定Person函數(shù)執(zhí)行上下文中的this為當前的Male創(chuàng)建的新對象晓猛。這樣通過Male構造出的對象饿幅,便能繼承擁有Person中的屬性,也就是name 和sex鞍帝。
14.補全代碼诫睬,實現(xiàn)繼承
function Person(name, sex){
// todo ...
}
Person.prototype.getName = function(){
// todo ...
};
function Male(name, sex, age){
//todo ...
}
//todo ...
Male.prototype.getAge = function(){
//todo ...
};
var li = new Male('Li', '男', 24);
li.printName();
代碼如下:
function Person(name,age){
this.name = name;
this.age = age;
}
Person.prototype.printName = function(){
console.log(this.name);
};
function Male(name,age,sex){
this.sex = sex;
Person.call(this,name,age);
}
Male.prototype = Object.create(Person.prototype);
Male.prototype.constructor = Male;
Male.prototype.printSex = function(){
console.log(this.sex);
};
var a = new Male('Li',24,'male');
a.printName(); //Li
也可封裝成一個函數(shù)使用:
function inherit(superType,subType){
var _superType = Object.create(superType.prototype);
_superType.constructor = superType;
subType.prototype = _superType;
}
function Person(name,age){
this.name = name;
this.age = age;
}
Person.prototype.printName = function(){
console.log(this.name);
};
function Male(name,age,sex){
this.sex = sex;
Person.call(this,name,age);
}
inherit(Person,Male);
Male.prototype.printSex = function(){
console.log(this.sex);
};
var a = new Male('Li',24,'male');
a.printName(); //Li