1:apply谬运、call 隙赁、bind有什么作用,什么區(qū)別
call 和 apply 都是為了改變某個函數運行時的上下文(context)而存在的梆暖,換句話說伞访,就是為了改變函數體內部 this 的指向。
apply轰驳、call 的區(qū)別
對于 apply厚掷、call 二者而言弟灼,作用完全一樣,只是接受參數的方式不太一樣蝗肪。例如袜爪,有一個函數定義如下:
var func = function(arg1, arg2) {
};
就可以通過如下方式來調用:
func.call(this, arg1, arg2);
func.apply(this, [arg1, arg2])
其中 this 是你想指定的上下文,他可以是任何一個 JavaScript 對象(JavaScript 中一切皆對象)薛闪,call 需要把參數按順序傳遞進去辛馆,而 apply 則是把參數放在數組里。
JavaScript 中豁延,某個函數的參數數量是不固定的昙篙,因此要說適用條件的話,當你的參數是明確知道數量時用 call 诱咏。而不確定的時候用 apply苔可,然后把參數 push 進數組傳遞進去apply 和 call 。
再來說說bind袋狞,bind() 方法與 apply 和 call 很相似焚辅,也是可以改變函數體內 this 的指向。
而bind苟鸯,MDN的解釋是:bind()方法會創(chuàng)建一個新函數同蜻,稱為綁定函數,當調用這個綁定函數時早处,綁定函數會以創(chuàng)建它時傳入 bind()方法的第一個參數作為 this湾蔓,傳入 bind() 方法的第二個以及以后的參數加上綁定函數運行時本身的參數按照順序作為原函數的參數來調用原函數。
apply砌梆、call默责、bind比較
那么 apply、call咸包、bind 三者相比較桃序,之間又有什么異同呢?何時使用 apply烂瘫、call葡缰,何時使用 bind 呢。簡單的一個栗子:
var obj = {
x: 81,
};
var foo = {
getX: function() {
return this.x;
}
}
console.log(foo.getX.bind(obj)()); //81
console.log(foo.getX.call(obj)); //81
console.log(foo.getX.apply(obj)); //81
三個輸出的都是81忱反,但是注意看使用 bind() 方法的,他后面多了對括號滤愕。
區(qū)別是温算,當你希望改變上下文環(huán)境之后并非立即執(zhí)行,而是回調執(zhí)行的時候间影,使用 bind() 方法注竿。而 apply/call 則會立即執(zhí)行函數。
總結一下:
- apply 、 call 巩割、bind 三者都是用來改變函數的this對象的指向的裙顽;
- apply 、 call 宣谈、bind 三者第一個參數都是this要指向的對象愈犹,也就是想指定的上下文;
- apply 闻丑、 call 漩怎、bind 三者都可以利用后續(xù)參數傳參;
bind 是返回對應函數嗦嗡,便于稍后調用勋锤;apply 、call 則是立即調用 侥祭。
2: 以下代碼輸出什么?
var john = {
firstName: "John"
}
function func() {
alert(this.firstName + ": hi!")
}
john.sayHi = func
john.sayHi()
輸出:John:hi!
誰在調用函數叁执,誰就是this,所以this是john矮冬,代碼執(zhí)行后彈出John:hi!
3: 下面代碼輸出什么谈宛,為什么
func()
function func() {
alert(this)
}
輸出 window
在函數被直接調用時this綁定到全局對象。在瀏覽器中欢伏,window 就是該全局對象
4:下面代碼輸出什么
document.addEventListener('click', function(e){
console.log(this);
setTimeout(function(){
console.log(this);
}, 200);
}, false);
輸出 document,window
綁定事件函數時入挣,this表示觸發(fā)此事件的DOM對象。
setTimeout硝拧、setInterval這兩個方法執(zhí)行的函數this也是全局對象
問題5:下面代碼輸出什么径筏,why
var john = {
firstName: "John"
}
function func() {
alert( this.firstName )
}
func.call(john)
輸出 John ,call方法可以在函數調用的時候將第一個參數設置為this值障陶,所以現在的this就是傳入的參數對象john滋恬。
6: 以下代碼有什么問題,如何修改
var module= {
bind: function(){
$btn.on('click', function(){
console.log(this) //this指什么
this.showMsg();
})
},
showMsg: function(){
console.log('加油');
}
}
這里的this指的是觸發(fā)此事件的DOM對象抱究,不是module恢氯。
this.showMsg(); //由于this是$btn,所以在執(zhí)行這句是會報錯鼓寺。
var module= {
bind: function(){
var _this=this;
$btn.on('click', function(){
console.log(_this) //this指什么
_this.showMsg();
})
},
showMsg: function(){
console.log('加油');
}
}
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("wang")
p.sayName();
Person是構造函數啸胧,也是一個對象赶站,這個對象里面存在一個prototype屬性,而構造函數內部定義了實例的屬性和方法纺念,這些屬性和方法是屬于該類的所有實例的特征贝椿;
p是通過構造函數Person構造出來的實例,也是擁有proto屬性陷谱。
p.__proto__ === Person.prototype;
prototype是構造函數內部的原型對象烙博,所以擁有contructor和proto屬性,其中contructor屬性指向構造函數Person叭首,proto指向該對象的原型习勤,即
Person.prototype.__proto__ === Object.prototype;
Person.prototype.constructor == Person
8: 上例中,對對象 p可以這樣調用 p.toString()焙格。toString是哪里來的? 畫出原型圖?并解釋什么是原型鏈图毕。
如圖所示,p.toString()方法是繼承構造函數Object的原型對象里定義的toString方法眷唉,首先p會找自己的toString方法予颤,如果沒有找到,會沿著proto屬性繼續(xù)到構造函數Person的prototype里找toString方法冬阳,如果還未找到蛤虐,再繼續(xù)往Person.prototype的proto即Object.prototype找toString方法,最后找到toString()方法肝陪。
原型鏈:由于原型對象本身也是對象驳庭,而每個javascript對象都有一個原型對象,每個對象都有一個隱藏的proto屬性氯窍,原型對象也有自己的原型饲常,而它自己的原型對象又可以有自己的原型,這樣就組成了一條鏈狼讨,這個就是原型鏈贝淤。在訪問對象的屬性時,如果在對象本身中沒有找到政供,則會去原型鏈中查找播聪,如果找到,直接返回值布隔,如果整個鏈都遍歷且沒有找到屬性离陶,則返回undefined。原型鏈一般實現為一個鏈表衅檀,這樣就可以按照一定的順序來查找枕磁。
9:對String做擴展,實現如下方式獲取字符串中頻率最高的字符
var str = 'ahbbccdeddddfg';
var ch = str.getMostOften();
console.log(ch); //d , 因為d 出現了5次
var str = 'ahbbccdeddddfg';
function String(str){
this.str=str;
}
String.prototype.getMostOften=function(){
var obj={};
for(var i=0;i<this.str.length;i++){
if(obj[this.str[i]]){
obj[this.str[i]]++;
}else{
obj[this.str[i]]=1;
}
}
console.log(obj);
var count=0,maxValue;
for(var key in obj){
if(obj[key]>count){
maxValue=key;
count=obj[key];
}
}
console.log("出現頻率最多的字符為"+maxValue+",共有"+count+"個");
}
str=new String(str);
var ch = str.getMostOften();
console.log(ch);
10: instanceOf有什么作用术吝?內部邏輯是如何實現的计济?
instanceOf:判斷一個對象是否為另一個對象的實例
instanceof 運算符用來測試一個對象在其原型鏈中是否存在一個構造函數的 prototype 屬性。
語法
object instanceof constructor
參數
object
要檢測的對象.
constructor
某個構造函數
內部邏輯
function instanceOf(obj,fn) {
var oldProto = obj.__proto__;
do {
if (oldProto=== fn.prototype){
return true;
}else {
oldProto = oldProto.__proto__
}
}while(oldProto){
return false;
}
11:繼承有什么作用?
作用:
- 子類擁有父類的屬性和方法排苍,不需要重復寫代碼沦寂,修改時也只需修改一份代碼
- 可以重寫和擴展父類的屬性和代碼,又不影響父類本身
12: 下面兩種寫法有什么區(qū)別?
//方法1
function People(name, sex){
this.name = name;
this.sex = sex;
this.printName = function(){
console.log(this.name);
}
}
var p1 = new People('wang', 2)
//方法2
function Person(name, sex){
this.name = name;
this.sex = sex;
}
Person.prototype.printName = function(){
console.log(this.name);
}
var p1 = new Person('hu', 27);
- 第一種方式是將所有的屬性和方法都寫在構造函數中淘衙,那么創(chuàng)建的每一個實例都會存有相同的方法传藏,會造成很大的內存浪費。
- 而第二種是將方法定義在原型上彤守,這樣只有在原型對象上才會有這個公有方法毯侦,所有實例對象都可以共享。
13: Object.create 有什么作用具垫?兼容性如何侈离?
Object.create() 方法使用指定的原型對象和其屬性創(chuàng)建了一個新的對象。
語法
Object.create(proto, [ propertiesObject ])
14: hasOwnProperty有什么作用筝蚕? 如何使用卦碾?
obj,hasOwnProperty(pro) 判斷某個對象是否含有指定的屬性但是該方法會忽略掉那些從原型鏈上繼承到的屬性
function People(){
this.name='lwk'
}
People.prototype.sayName=function(){console.log(this.name)}
var p = new People()
p.hasOwnProperty('name')//true
p.hasOwnProperty('sayName')//false
15:如下代碼中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方法,指定Person方法中的this為Male起宽,并傳入參數sex洲胖,age
16: 補全代碼,實現繼承
unction Person(name, sex){
this.name = name;
this.sex = sex;
}
Person.prototype.getName = function(){
console.log('name:' + 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;
Male.prototype.getAge = function(){
console.log("age:"+this.age);
};
Male.prototype.printName = function(){
this.getName();
this.getAge();
}
var ruoyu = new Male('王虎', '男', 26);
ruoyu.printName();