callee和caller屬性以及this關(guān)鍵字的理解
最近一段時(shí)間寫代碼,也開始注意一些以前不想動(dòng)腦理解的基礎(chǔ)知識了。加油呀~~~
1. callee
- callee是實(shí)參對象arguments的一個(gè)屬性(arguments.callee);
- callee返回當(dāng)前正在執(zhí)行的函數(shù);
- callee有利于做匿名函數(shù)的遞歸。
1.1 驗(yàn)證arguments.callee
function getCallee() {
return arguments.callee;
}
let callee = getCallee();
console.log(callee === getCallee); // true
1.2 利用arguments.callee實(shí)現(xiàn)遞歸完成階乘函數(shù)
// 常用方法
function factorial1(num) {
return num > 1 ? num * factorial1(num - 1) : 1;
}
console.log("factorial1(5) = " + factorial1(5)); // 120
// 使用arguments.callee
function factorial2(num) {
return num > 1 ? num * arguments.callee(num - 1) : 1; // 120
}
console.log("factorial2(5) = " + factorial2(5));
2. caller
- caller是Function實(shí)例的一個(gè)屬性;
- functionName.caller: functionName是當(dāng)前正在執(zhí)行的函數(shù);
- caller返回一個(gè)對函數(shù)的引用,該函數(shù)調(diào)用了當(dāng)前函數(shù)。如果該函數(shù)在頂層被調(diào)用則返回null。
2.1 使用caller的測試代碼
function testCaller(msg) {
console.log(msg + testCaller.caller);
}
testCaller("頂層調(diào)用:"); // 頂層調(diào)用:null
function callCaller() {
testCaller("callCaller調(diào)用:");
}
callCaller();
// ===打印結(jié)果===
/*callCaller調(diào)用:function callCaller() {
testCaller("callCaller調(diào)用:");
}*/
3. this
理解this代表什么真的很重要。以下內(nèi)容僅涉及在前端開發(fā)中this的調(diào)用方式,喜歡動(dòng)腦的你們可以試一試拿這些應(yīng)用場景和之前接觸的編程語言來做一個(gè)對比呀~
- this是Javascript語言的一個(gè)關(guān)鍵字。它代表函數(shù)運(yùn)行時(shí),自動(dòng)生成的一個(gè)內(nèi)部對象,只能在函數(shù)內(nèi)部使用。隨著函數(shù)使用場合的不同,this的值會(huì)發(fā)生變化。但是有一個(gè)總的原則,那就是this指的是,調(diào)用函數(shù)的那個(gè)對象(是執(zhí)行環(huán)境,而非聲明環(huán)境)。
3.1 標(biāo)簽屬性注冊事件調(diào)用
<button id="button1" type="button" name="button1" onclick="btnClick1()">button1</button>
<button id="button2" type="button" name="button2" onclick="btnClick2(this)">button2</button>
<script>
// 標(biāo)簽屬性注冊事件調(diào)用
function btnClick1() {
console.log(this);
}
function btnClick2(dom) {
console.log(this);
console.log(dom);
}
var eleButton1= document.getElementById("button1");
var eleButton2= document.getElementById("button2");
eleButton1.onmouseover = btnClick1; // dom
eleButton2.attachEvent("onmouseover", btnClick1); // window
eleButton2.addEventListener("mouseover", btnClick1, false); // dom
</script>
注:button1 點(diǎn)擊的時(shí)候輸出:window對象、button2 點(diǎn)擊的時(shí)候輸出:window對象 和 當(dāng)前dom元素。用attachEvent、addEventListener方法要先進(jìn)行判斷哈,不要直接就寫了。
- 通過標(biāo)簽屬性注冊事件調(diào)用,方法體中的this值指向window對象;
- js代碼中給dom元素綁定事件屬性,方法體中的this指向當(dāng)前dom元素;
- IE低版本中利用attachEvent給dom元素注冊事件,方法體中的this指向window對象;
- 利用addEventListener給dom元素注冊事件,方法體中的this指向當(dāng)前dom元素;
- 最后,如果你利用jquery綁定事件,回調(diào)函數(shù)中的this值是當(dāng)前dom元素。
3.2 普通函數(shù)調(diào)用
function fun1() {
console.log("普通函數(shù)調(diào)用" + this);
}
fun1(); // 普通函數(shù)調(diào)用[object Window]
- 直接調(diào)用普通函數(shù)時(shí),this是指向window對象的;
- 當(dāng)沒有明確的執(zhí)行時(shí)的當(dāng)前對象時(shí),this指向全局對象window(非瀏覽器情況下(例如:nodejs)中全局變量并非window對象,而是叫“全局變量”(the global object)global)。
3.3 作為對象方法調(diào)用
var age = 10;
var tom = {
age: 20,
printAge: function () {
console.log(this.age);
}
};
tom.printAge(); // 20
- 函數(shù)作為某個(gè)對象的方法調(diào)用,這時(shí)this就指這個(gè)上級對象。
3.4 作為構(gòu)造函數(shù)調(diào)用-new
var name = "window";
function People(name) {
this.name = name;
}
People.prototype.printName = function () {
console.log(this.name);
};
var people1 = new People("tom");
console.log(name); // window
console.log(people1.name); // tom
people1.printName(); // tom
- 所謂構(gòu)造函數(shù),就是通過這個(gè)函數(shù)生成一個(gè)新對象(object)。這時(shí),this就指這個(gè)新對象。即new關(guān)鍵字后的構(gòu)造函數(shù)中的this指向用該構(gòu)造函數(shù)構(gòu)造出來的新對象。
3.5 apply、call 調(diào)用
var color = "red";
var car = {
color: "blue",
printColor: function () {
console.log(this.color);
}
};
car.printColor(); // blue
car.printColor.call(); // red
car.printColor.call(this); // red
car.printColor.call(car); // blue
car.printColor.apply(); // red
car.printColor.apply(this); // red
car.printColor.apply(car); // blue
注:apply()、call()是函數(shù)對象的一個(gè)方法,作用是改變函數(shù)的調(diào)用對象,它的第一個(gè)參數(shù)就表示改變后的調(diào)用這個(gè)函數(shù)的對象。因此,this指的就是這第一個(gè)參數(shù)。apply()、call()的參數(shù)為空時(shí),默認(rèn)調(diào)用全局對象。
3.6 eval函數(shù)
var age = 10;
var tom = {
age: 20,
printAge: function () {
eval("console.log(this.age)");
}
};
tom.printAge(); // 20
- eval函數(shù)執(zhí)行的時(shí)候,this綁定到當(dāng)前作用域的對象上。
3.7 setTimeout、setInterval和匿名函數(shù)
var city = "四川";
var bob = {
city: "北京",
printCity: function () {
var that = this; // 匿名函數(shù)中使用對象bob
(function () {
console.log("匿名函數(shù):" + this.city); // 四川
console.log("匿名函數(shù)-that:" + that.city); // 北京
}());
setTimeout(function () {
console.log("setTimeout:" + this.city); // 四川
}, 2000);
setInterval(function () {
console.log("setInterval:" + this.city); // 四川
}, 5000)
}
};
bob.printCity();
- 在瀏覽器中setTimeout、setInterval和匿名函數(shù)執(zhí)行時(shí)的當(dāng)前對象是全局對象window(瀏覽器中全局變量可以當(dāng)成是window對象下的變量);
最后:this的應(yīng)用場景有很多,在平時(shí)開發(fā)中一定要注意,避免入坑。