1. apply、call 、bind有什么作用,什么區(qū)別?
call ,apply的作用:調(diào)用一個(gè)函數(shù),傳入函數(shù)執(zhí)行上下文及參數(shù)
第一個(gè)參數(shù)都是希望設(shè)置的this對(duì)象,不同之處在于call方法接收參數(shù)列表,而apply接收參數(shù)數(shù)組
-
call
fun.call(thisArg[, arg1[, arg2[, ...]]]) -
apply
fun.apply(thisArg, [argsArray])
例子:
//call()
window.name = "1";
var a = {name: "2"};
function sayName(){
alert(this.name);
}
sayName(); //1
sayName.call(this); // 1
sayName.call(a); //2
//apply()
var numbers = [1,5,6,2,3,7,8]
var max = Math.max.apply(null,numbers) //8
bind的作用:返回一個(gè)新函數(shù),并且使函數(shù)內(nèi)部的this為傳入的
第一個(gè)參數(shù)
例子:
var obj1 = {
name: 'Byron',
fn : function(){
console.log(this);
}
};
obj1.fn(); //obj1
var fn2 = obj1.fn;
fn2(); //window
var fn3 = obj1.fn.bind(obj1);
fn3(); //obj1
2. 以下代碼輸出什么?
var john = { firstName: "John" } function func() { alert(this.firstName + ": hi!") } john.sayHi = func john.sayHi() //彈出 John:hi! //因?yàn)閒unc賦給了john對(duì)象的sayHi屬性,執(zhí)行john.sayHi() 時(shí) 是在john對(duì)象上調(diào)用的,此時(shí)的上下文this是john了.
3. 下面代碼輸出什么,為什么?
func() //執(zhí)行函數(shù),當(dāng)前執(zhí)行環(huán)境是window,alert [object Window] function func() { alert(this) }
4. 下面代碼輸出什么?
document.addEventListener('click', function(e){ console.log(this); //document,點(diǎn)擊事件回調(diào)方法執(zhí)行時(shí),this指向document setTimeout(function(){ console.log(this); //window,定時(shí)器回調(diào)函數(shù)執(zhí)行時(shí),this指向window }, 200); }, false);
5. 下面代碼輸出什么,why?
var john = { firstName: "John" } function func() { alert( this.firstName ) } func.call(john) //John, func.call(john)方法執(zhí)行時(shí),由于傳入了john對(duì)象作為參數(shù),func()方法中的this指向john對(duì)象
6. 以下代碼有什么問題,如何修改
var module= { bind: function(){ $btn.on('click', function(){ console.log(this) //this指什么 this指$btn對(duì)象 this.showMsg(); }) },
showMsg: function(){ console.log('饑人谷'); } }
問題:在$btn的點(diǎn)擊回調(diào)函數(shù)中,this.showMsg()方法執(zhí)行時(shí)會(huì)報(bào)錯(cuò),this.showMsg is not a function
var module= { bind: function(){ let self = this; //self對(duì)象指向module對(duì)象 $btn.on('click', function(){ console.log(this) //this指什么 this指$btn對(duì)象 self.showMsg(); //調(diào)用module的showMsg()方法 }) }, showMsg: function(){ console.log('饑人谷'); } }
原型鏈相關(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(); //p是Person的實(shí)例,所以繼承Person原型鏈上的屬性和方法。 //關(guān)聯(lián): Person.prototype.constructor == Person, Person.prototype == p.__proto__, p.__proto__.constructor == Person, Person.prototype.__proto__ == Object.prototype, Object.prototype.constructor == Object, Object.prototype.__proto__ == null
8. 上例中,對(duì)對(duì)象 p可以這樣調(diào)用 p.toString()。toString是哪里來的? 畫出原型圖?并解釋什么是原型鏈。
答:構(gòu)造函數(shù)的原型自帶一個(gè)指針指向object的原型,因而toString是從object的原型里繼承而來。

原型鏈:JS在創(chuàng)建對(duì)象(不論是普通對(duì)象還是函數(shù)對(duì)象)的時(shí)候,都有一個(gè)叫做proto的內(nèi)置屬性,用于指向創(chuàng)建它的函數(shù)對(duì)象的原型對(duì)象prototype。在訪問一個(gè)對(duì)象屬性的時(shí)候,如果對(duì)象本身沒有找到這個(gè)屬性,就會(huì)沿著原型鏈一層一層的尋找。
9. 對(duì)String做擴(kuò)展,實(shí)現(xiàn)如下方式獲取字符串中頻率最高的字符
var str = 'ahbbccdeddddfg'; String.prototype.getMostOften = function(){ var obj = {}; for(var i=0,k;i<this.length;i++){ k = this[i]; if(obj[k]){ obj[k]++ }else{ obj[k] = 1 } } console.log(obj);
`var max = 0,key;
for(var k in obj){
if(obj[k]>max){
max = obj[k];
key = k;
}
}
return key;
}
var ch = str.getMostOften();
console.log(ch); //d , 因?yàn)閐 出現(xiàn)了5次`
10. instanceOf有什么作用??jī)?nèi)部邏輯是如何實(shí)現(xiàn)的?
instanceof運(yùn)算符返回一個(gè)布爾值,表示指定對(duì)象是否為某個(gè)構(gòu)造函數(shù)的實(shí)例。instanceof的原理是檢查原型鏈,對(duì)于那些不存在原型鏈的對(duì)象,就無法判斷。
var arr = [1, 2, 3]; arr instanceof Array; //true 其實(shí)是判斷arr.__proto__===Array.prototype arr instanceof Object; //true 判斷arr.__proto__.__proto__===Object.prototype

繼承相關(guān)問題
11.繼承有什么作用?
繼承是指一個(gè)對(duì)象直接使用另一對(duì)象的屬性和方法。通過繼承,可以使子類共享父類的屬性和方法,可以覆蓋(重寫)和擴(kuò)展父類的屬性和方法,減少內(nèi)存的使用,提高代碼復(fù)用性。
12.下面兩種寫法有什么區(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:一個(gè)寫在構(gòu)造函數(shù)內(nèi)部的實(shí)例對(duì)象上。另一個(gè)寫在構(gòu)建函數(shù)的prototype對(duì)象上。 //前者在每生成一個(gè)實(shí)例之后實(shí)例的printName就新占用內(nèi)存。 //后者每生成一個(gè)實(shí)例后會(huì)共享構(gòu)造函數(shù)prototype對(duì)象上的printName方法,以達(dá)到節(jié)省內(nèi)存的效果;
13.Object.create 有什么作用?兼容性如何?
Object.create() 方法使用指定的原型對(duì)象和其屬性創(chuàng)建了一個(gè)新的對(duì)象。即傳入類的原型后,可以克隆原型對(duì)象參數(shù)并返回一個(gè)新的對(duì)象
例子:
//Shape - 父類 function Shape() { this.x = 0; this.y = 0; }
`Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
console.info("Shape moved.");
};`
// Rectangle - 子類 function Rectangle() { Shape.call(this); //call 父類的 constructor. }
Rectangle.prototype = Object.create(Shape.prototype);
var rect = new Rectangle();
rect instanceof Rectangle //true. rect instanceof Shape //true.
rect.move(1, 1); //Outputs, "Shape moved."
兼容性:各大瀏覽器的最新版本(包括IE9)都兼容了這個(gè)方法。如果遇到老式瀏覽器,可以用下面的代碼兼容:
if(!Object.create){ Object.create = function(obj){ function F(){}; F.prototype = obj; return new F(); } }
14. hasOwnProperty有什么作用? 如何使用?
答:
對(duì)象實(shí)例的hasOwnProperty方法返回一個(gè)布爾值,用于判斷某個(gè)屬性定義在對(duì)象自身,還是定義在原型鏈上。
var people = { name:'teren' } people.hasOwnProperty('name')//true people.hasOwnProperty('toString')//false Object.getPrototypeOf(people).hasOwnProperty('toString')//true
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ù)Person在構(gòu)造函數(shù)Male作用域下執(zhí)行,以實(shí)現(xiàn)構(gòu)造函數(shù)的繼承; this.age = age; }
16. 補(bǔ)全代碼,實(shí)現(xiàn)繼承
function Person(name, sex){ this.name = name; this.sex = sex; } Person.prototype.getName = function(){ return this.name }; function Male(name, sex, age){ Person.call(this,name,sex); this.age = age; } //function inherit(superType, subType) { var _prototype = Object.create(superType.prototype); _prototype.constructor = subType; subType.prototype = _prototype; } inherit(Person, Male);// Male.prototype = Object.create(Person.prototype); Male.prototype.constructor = Male; Male.prototype.getAge = function(){ return this.age }; Male.prototype.getAge = function(){ console.log(this.name) }; var ruoyu = new Male('若愚', '男', 27); ruoyu.getName();