問題1: apply、call 、bind有什么作用,什么區別
問題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]
}
可以這么理解:在func函數里沒有找到this,所以往全局函數找,于是this就是window,也可以這么理解func.call(null),于是乎this就是window了,還可以這么理解:它就是一個簡單的函數調用,此時的this就是window了...
問題4:下面代碼輸出什么
document.addEventListener('click', function(e){
console.log(this);//document,這個屬于方法調用模式,this指向事件源DOM對象,可以這么理解:obj1.fn.apply(obj1);
setTimeout(function(){
console.log(this);//window,這個屬于把函數賦值之后調用的回調函數,this指向window,可以這么理解:f1.call(null,f2)
}, 200);
}, false);
問題5:下面代碼輸出什么,why
var john = {
firstName: "John"
}
function func() {
alert( this.firstName )
}
func.call(john)//john
因為func將this綁定為john這個對象了,因此this.firstName => john.firstName
問題6: 以下代碼有什么問題,如何修改
var module= {
bind: function(){
$btn.on('click', function(){
console.log(this) //this指$btn
this.showMsg();
})
},
showMsg: function(){
console.log('饑人谷');
}
}
this.showMsg()這個this指的是$btn,而$btn沒有showMsg()這個方法,可以在函數后面bind(module),也可以將this.showMsg()改為module.showMsg.call(module)
,也可以將module的this保存起來為that,最后用that.showMsg()
去執行
問題7:有如下代碼,解釋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();
每個構造函數有一個prototype屬性,指向一個對象,被稱為原型對象,原型對象有一個構造器constructor指向該構造函數,每個對象都有一個__proto__屬性,指向創建該對象的構造函數的原型對象。
因此有以下關聯:
p.__proto__ == Person.prototype
Person.prototype.constructor == Person
p.constructor == Person//從原型鏈上查找
問題8: 上例中,對對象 p可以這樣調用 p.toString()。toString是哪里來的? 畫出原型圖?并解釋什么是原型鏈。
畫圖太麻煩了,還是用代碼代替吧...
//首先會查找自身有沒有toString()這個方法
//然后根據__proto__一級一級的向上查找,直到找到Object.prototype,如果還是沒找到就返回null,期間找到了就調用那個方法
p.__proto__ == Person.prototype//找到父元素的原型對象,沒有這個方法,于是繼續查找
p.__proto__.__proto__ == Object.prototype//找到了Object對象的原型對象
p.__proto__.__proto__.toString()== Object.prototype.toString()
//最后在Object.prototype中找到了toString()這個方法,所以此時就可以調用toString這個方法了
原型鏈:由于原型對象本身也是對象,而每個javascript對象都有一個原型對象,每個對象都有一個隱藏的__proto__屬性,原型對象也有自己的原型,而它自己的原型對象又可以有自己的原型,這樣就組成了一條鏈,這個就是原型鏈。在訪問對象的屬性時,如果在對象本身中沒有找到,則會去原型鏈中查找,如果找到,直接返回值,如果整個鏈都遍歷且沒有找到屬性,則返回undefined。原型鏈一般實現為一個鏈表,這樣就可以按照一定的順序來查找。
上面的p.toString()這個方法的查找就是一個很明顯的原型鏈的例子
問題9:對String做擴展,實現如下方式獲取字符串中頻率最高的字符
String.prototype.getMostOften = function(){
var arr = this.split('')
var results = {}
var max = 0
var result
for(var i=0;i<arr.length;i++){
if(arr[i] in results){
results[arr[i]]++
}else{
results[arr[i]] = 0
}
}
for(var j in results){
if(results[j] > max){
max = results[j]
result = j
}
}
return result
}
var str = 'ahbbccdeddddfg';
var ch = str.getMostOften();
console.log(ch); //d , 因為d 出現了5次
問題10: instanceOf有什么作用?內部邏輯是如何實現的?
instanceof 運算符與 typeof 運算符相似,用于識別正在處理的對象的類型。與 typeof 方法不同的是,instanceof 方法要求開發者明確地確認對象為某特定類型
A instanceof B的判斷規則是:沿著A的__proto__這條線來找,同時沿著B的prototype這條線來找,如果兩條線能找到同一個引用,即同一個對象,那么就返回true。如果找到終點還未重合,則返回false
因此:
Object instanceof Object
Object instanceof Function
Function instanceof Object
Function instanceof Function
function io(arr,fn){
if(arr.__proto__){
if(arr.__proto__ === fn.prototype){
return true
}else{
return io(arr.__proto__,fn)
}
}else{
return false
}
}
var arr = []
console.log(io(arr,Array))
console.log(io(arr,Object))
console.log(io(arr,String))
問題11:繼承有什么作用?
繼承機制使得不同的實例可以共享構造函數的原型對象的屬性和方法,提高了代碼的復用性
問題12: 下面兩種寫法有什么區別?
//方法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方法,一個直接寫在構造函數內部的實例對象上,另一個部寫在構造函數的prototype對象上,前者在每生成一個實例之后實例的printName就占用內存,而后者每生成一個實例后會共享構造函數prototype對象上的printName方法,以達到節省內存的效果,因此公共方法寫在原型對象上更好。
問題13: Object.create 有什么作用?兼容性如何?
Object.create() 方法會使用指定的原型對象及其屬性去創建一個新的對象,
各大瀏覽器的最新版本(包括IE9)都部署了這個方法,可以寫一個polyfill解決低版本瀏覽器問題
if(!Object.create){
Object.create = function(obj){
function F(){};
F.prototype = obj;
return new F();
}
}
問題14: hasOwnProperty有什么作用? 如何使用?
對象實例的hasOwnProperty方法返回一個布爾值,用于判斷某個屬性定義在對象自身,還是定義在原型鏈上
//這樣寫可以排除原型鏈上的屬性
var obj = {}
for(var i in obj){
if(Object.hasOwnProperty(obj[i])){
// 繼續執行
}
}
問題15:如下代碼中call的作用是什么?
function Person(name, sex){
this.name = name;
this.sex = sex;
}
function Male(name, sex, age){
Person.call(this, name, sex); //this指的實例,將Person在這里執行了一遍,實例就有了Person的屬性
//借用Person函數的屬性,使Male函數能夠執行Person上的初始化代碼,實現構造函數屬性繼承
this.age = age;
}
問題16: 補全代碼,實現繼承
//寄生組合繼承:
function Person(name, sex){
this.name = name
this.sex = sex
}
Person.prototype.getName = function(){
return this.name;
};
Person.prototype.printName = function () {
console.log(this.name)
}
// 屬性在這兒繼承
function Male(name, sex, age){
Person.call(this,name,sex)
this.age = age
}
// 方法在這繼承
Male.prototype = Object.create(Person.prototype)
Male.prototype.constructor = Male;//constructor將constructor復原
Male.prototype.getAge = function(){
console.log(this.age)
};
var ruoyu = new Male('若愚', '男', 27);
ruoyu.printName();
講講Function和Object的關系
對象是函數創建的,而函數卻又是一種對象,每個函數function都有一個prototype,每個對象都有一個__proto__,它指向創建該對象的函數的prototype,Object.prototype卻是一個特例——它的__proto__指向的是null,因此Object.prototype.__proto__ === null
.
函數也是一種對象,函數也有__proto__嗎?當然有,函數也不是從石頭縫里蹦出來的,函數也是被創建出來的。誰創建了函數呢?——Function,對象的__proto__指向的是創建它的函數的prototype,因此:Object.__proto__ === Function.prototype
所有函數的__proto__都指向Function.prototype,包括Object這個所有對象的祖宗,Object.__proto__指向Function.prototype,唉,怎么還有一個……Function.proto指向Function.prototype?這不成了循環引用了?對!是一個環形結構。
其實稍微想一下就明白了。Function也是一個函數,函數是一種對象,也有__proto__屬性。既然是函數,那么它一定是被Function創建。所以Function是被自身創建的。所以它的__proto__指向了自身的Prototype,因此:Function.__proto__ === Function.prototype
Function是每個函數的祖宗,Object是每個對象的祖宗,每個函數的__proto__都指向Function.prototype,每一個對象包括原型對象都指向Object.prototype,那么Function.prototype指向的對象,它的__proto__是不是也指向Object.prototype?答案是肯定的。因為Function.prototype指向的對象也是一個普通的被Object創建的對象
因此:Function.prototype.__proto__ === Object.prototype
最后再三強調一下:每個對象都有一個__proto__屬性,指向創建該對象的構造函數的原型對象,因為每個函數都是由Function創造的,因此所有函數的__proto__都指向Function.prototype,因為所有對象都是由Object創造的,因此所有對象的__proto__都指向Object.prototype,如果理解了下面的等式就理解了這句話:
Object.__proto__ === Function.prototype
Function.prototype.__proto__ === Object.prototype
當然Function和Object有一些特殊,所有函數的__proto__都指向Function.prototype,那么它自己呢,同樣如此;所有對象都是由Object創造的,因此所有對象的__proto__都指向Object.prototype,那么它自己呢,此時它卻指向null!!!記住下面兩個代碼:
Function.__proto__ === Function.prototype
Object.prototype.__proto__ === null