文章目錄
JavaScritp 中的 this
總結一句話(永真給的信)
大雪紛飛,永真在井上面丟垃圾一封信,信上寫着如下內容:
誰最終調用,
this
就指向誰。
那麼如何理解永真寫的話呢?請接着往下看~
默認綁定(指向少主window)
我(this)的職責就是保護
指向少主,少主喜歡用window玩遊戲,姑且叫少主window吧。
- 只狼聽從了義父之前的命令,好好保護少主,所以
this
指針(只狼)默認綁定(跟隨)的是window
(少主)
console.log(this); // window
少主活了幾百年,還那麼年輕,而且會的東西很多少主還會a
函數,寫全局函數的話,也是指向的window
function a() {
console.log(this);
}
a() // window
//實際上是 window.a(); 我們可以展開window看看
少主還會做日晷,沙漏等小工具,用來做定時器, 定時器是window
(少主)的方法,所以this
也會指向window
。
// setInterval 也是 window 下的方法
setInterval(function () {
console.log(this); // window
}, 1000)
嚴格模式(變若之子)
爲了追尋長生不老,山上的僧人開始作妖,嚴格實驗了好多小孩,最後就一個小女孩活了下來,成了變若之子(假的皇子)
- 嚴格模式下的
this
指向undefined
(因爲是假的皇子,所以就undefined
了)
function a() {
"use strict";
console.log(this);
}
a() // undefined
console.log(this);
補充:什麼是嚴格模式
簡單來說就是爲了更好的規範 JavaScript 語言的書寫,具體請參考阮一峯的嚴格模式詳解。
隱式綁定(葦名弦一郎)
情景:我們帶着皇子一路小跑,走出隧道,只見弦一郎在堵門,
(簡介,遊戲名《只狼》,第一個BOSS的名字)
開門見山!!先來打葦名弦一郎。
var name = '我是全局name'
function fn() {
var name = '我是fn';
console.log(this.name);
}
var objA = {
name:'我是objA',
showA:fn
}
var objB = {
name:"我是B對象",
showB:objA
}
objB.showB.showA()
請問最終打印的是什麼呢?這裏我先不告訴你們答案,先跟着我一步一步往下走~
分支1:沒打過弦一郎(
沒做對):失去手臂,等待佛雕師(作者)給你安義肢(講解)。
分支2:打過弦一郎:同樣失去手臂(不要怪我卑鄙!我叫屑一狼),等待佛雕師…
戰果:經驗 +0,金幣 -0,金錢 -0,HP -0,失去真手臂
次日:看到淡淡的油燈光亮,發現自己躺在破舊寺廟的草蓆上,並且獲得了義肢。
戰果:獲得義肢,HP +100
來看一下栗子(葦名城雜兵,經驗怪 ):
function fn() {
console.log(this);
}
var obj = {
show: fn
};
obj.show(); // {show: ƒ}
// this 指向的關鍵在於是誰最終執行的
成功忍殺
看懂了這個:金錢+5,經驗+5
第二個栗子(葦名城雜兵,經驗怪 ):
function fn() {
console.log(this);
}
var obj = {
show: fn() // 因爲fn才最終執行者,括號代表執行!而 fn 是 window 下的函數
};
obj.show; // window
成功忍殺:HP+5,金錢+5,經驗+5
獲得少主給的:傷葫蘆,楔丸
此時來到了葦名城 城邑外圍 城門道,遇到了第一個boss(河源田直盛)
function fn() {
console.log(this.name);
}
var objA = {
name:'我是A對象',
showA:fn
}
var objB = {
name:"我是B對象",
showB:objA
}
objB.showB.showA() // 我是A對象
// 爲啥指的是objA呢?
// 你要清除是誰最終調用的fn,是不是objA裏纔有fn啊,最終調用的也是objA!所以指向就是objA。
成功忍殺
看懂了這個:HP+10,金錢+10,經驗+10
獲得技能:識破
總結:以上例子可以說明,this的指向跟函數寫在哪裏沒啥關係,關鍵在於最終調用者是誰!
隱式丟失(赤鬼 + 鬼庭形部雅孝)
情景:來到了被鎖住的赤鬼。發現兜裏沒有月隱糖,也沒有噴火器,沒關係,有閃避+突刺,超級逃課打法。
var name = '我是全局name';
var obj = {
name:'我是obj的name',
fn:function () {
console.log(this.name);
}
}
var xxx = obj.fn;
xxx(); // 我是全局name
// 這裏爲什麼是全局name呢
// 因爲xxx是最終調用者,而xxx屬於window,所以this指向的是window
成功忍殺:獲得佛珠,忍者之藥理知識•甲
失敗:死,(少主的龍血之力,無盡復活)
接着來到下一關
情景:來到了葦名城 正門外城區,遇到鬼庭形部雅孝,不慌,追的驢的尾巴,砍就完事兒了,
逃課
var name = '我是全局name';
var obj = {
name:'我是obj的name',
fn:function () {
console.log(this.name);
}
}
function xxx(param) {
// 2. 然後在這裏執行函數
param();
// 相當於 window.param()
}
// 1. 此時我把函數體當成參數傳遞進去了
xxx(obj.fn) // 我是全局name
成功忍殺:戰鬥記憶:鬼庭形部雅孝(攻擊力強化),機關筒(義手強化工具)。
失敗:死,(少主的龍血之力,無盡復活)
接着到了火牛關
情景:火牛血厚,建議買鞭炮(
前面的都看懂了)
var name = '我是全局name';
var obj = {
name:'我是obj的name',
fn:function () {
console.log(this.name);
}
};
var obj1 = {
name:"福山潤"
};
obj1.xxx = obj.fn;
obj1.xxx(); // 福山潤
成功忍殺:佛珠,忍者藥理·乙。
失敗:死,減一半的¥
顯式綁定(櫻龍,白蛇)
我們可以通過call
(幹柿子 )、apply
(米 )和bind
(櫻龍之淚 )方法更改指針的指向(不同結局)。
// 顯示轉換
var objA = {
name: "aaa"
};
var objB = {
name: "bbb"
};
var objC = {
name: "ccc"
};
var name = '我是全局name';
function fn() {
console.log(this.name);
}
fn(); // 我是全局name
fn.call(objA); // aaa
fn.apply(objB); // bbb
fn.bind(objC)(); // ccc
成功忍殺梟,櫻龍,白蛇:獲得櫻樹枝,櫻龍之淚,鮮柿子,月隱糖
失敗:死,(少主的龍血之力,無盡復活),金錢 -1/2
某些方法也可以顯式的更改指針,比方說forEach
var obj = {
name:'鈴木雅之'
};
var arr = [1,2,3,4];
arr.forEach(function () {
console.log(this.name); // 4 * 鈴木雅之
},obj)
越到後期,遊戲所需要的技巧就越高,熟練度也就越重要,(不我就是平a格擋流 )
顯式綁定的優先級 大於 隱式綁定的優先級,顯式>隱式>默認
var objA = {
name:'aaa',
fn:function () {
console.log(this.name);
}
}
var objB = {
name:'bbb'
}
// 前面的是objA.fn() ,隱式綁定,省略了括號,
// 後面的call()是顯示綁定
// 當顯式隱式都存在的時候,顯式優先級更大
objA.fn.call(objB) //bbb
Dom節點中的this(雜兵)
發現個小胖子,他跟同伴走丟了,他想要我給他找彩色風車…
其實這個跟之前講的蠻像的,我就在這裏再重複一下叭
<body>
<div class="btn">點我</div>
</body>
<script>
function show(){
console.log(this);
}
document.querySelector('div').addEventListener('click', show);
// <div class="btn">點我</div>
document.querySelector('div').addEventListener('click', show());
// window
</script>
成功忍殺:臥槽小胖子好可憐的,
別殺了,騙到商人那裏打掃戰場
失敗:良心受到譴責嗯~ o( ̄▽ ̄)o
new
來到了葦名之底 毒沼,獅子猿 new 出一個小獅子猿,二打一,太難了
function Person() {
// 1. 剛開始這裏的this指向的是 window
// 因爲這是函數啊
this.name = '堺雅人'
}
// 2. 然後通過new方法改變了 this 指向
var p = new Person();
console.log(p.name);
成功忍殺:戰鬥記憶:無首獅子猿,佛珠*2,血刀術(使用不死斬斷絕不死後獲得)
失敗:死,減一半的¥
箭頭函數(另類)
來到了葦名城 城邑外圍 城門道,看到個沒有頭的傢伙,無首,尼瑪打了一架,被戳了菊花,屏幕上出現了:菜
取決於:外層(上層)作用域中的this
,和他本身沒有關係
var name = 'www';
function fn() {
// 這裏就是箭頭函數上層作用域
// 這裏的 this 指向 window
console.log(this.name);
return () => {
console.log(this.name);
}
}
var objA = {
name:'aaa'
};
var xxx = fn(); // www
xxx(); // www
成功忍殺:哼將之降靈
失敗:死,減一半的¥
var name = 'www';
function fn() {
// 這裏就是箭頭函數上層作用域
// 這裏的 this 通過 call 方法指向了 objA
console.log(this.name);
return () => {
console.log(this.name);
}
}
var objA = {
name:'aaa'
};
var xxx = fn.call(objA); // aaa
xxx(); // aaa
情景:最後來到了葦名城主城 貯水城區,弦一郎喝了變若(
弱) 水,劍聖葦名一心想要實現他兒子的最後的願望,就是守護這片土地,於是重返戰場…
- 箭頭函數中的
this
它既是喫軟飯的,也很專一
var name = 'www';
function fn() {
// 喫軟飯的箭頭函數this:一直跟隨着上層作用域
// 這裏就是箭頭函數上層作用域
console.log(this.name);
return () => {
console.log(this.name);
}
}
var objA = {
name:'aaa'
};
var objB = {
name:'bbb'
};
// 此時xxx就是箭頭函數
var xxx = fn.call(objA); // aaa
// 我這時修改箭頭函數的指向,然並卵
// 箭頭函數中的this很專一,取決於外層作用域的指向
xxx.call(objB); // aaa
- 如果想改箭頭函數的
this
,那麼只能修改上層作用域的this
,比方說上面的例子
// 只有修改上層作用域的this,才能改變箭頭函數的this
var xxx = fn.call(objb); // bbb
// 即使是修改了箭頭函數的指向也沒用
xxx.call(objA); // bbb
成功忍殺:戰鬥記憶:劍聖 葦名一心,祕傳·龍閃(技能)。
失敗:死,我死了200多回hhhh。
通關,趕快去救小皇子~
補充
執行上下文
執行上下文是指 函數調用時 在執行棧中產生的變量對象,這個變量對象我們無法直接訪問,但是可以訪問其中的變量、this
對象等。
let fn, bar; // 1、進入全局上下文環境
bar = function(x) {
let b = 5;
fn(x + b); // 3、進入fn函數上下文環境
};
fn = function(y) {
let c = 5;
console.log(y + c); //4、fn出棧,bar出棧
};
bar(10); // 2、進入bar函數上下文環境
每次函數調用時,執行棧棧頂都會產生一個新的執行上下文環境,JavaScript引擎會以棧的方式來處理它們,這個棧,我們稱其爲函數調用棧(call stack)。棧底永遠都是全局上下文,而棧頂就是當前處於活動狀態的正在執行的上下文,也稱爲活動對象(running execution context,圖中藍色的塊),區別與底下被掛起的變量對象(執行上下文)。
字面量
用於表達源代碼中一個固定值的表示法