一文詳解JavaScript中this指向的問題
前提:文章討論的都是非嚴(yán)格模式下this指向
1. 默認(rèn)綁定
例子1
var fn = function () { console.log(this === window); }; fn(); // true
例子2
let fn = function () { console.log(this === window); }; fn(); // true
例1使用var定義在全局作用域中,例2使用let定義在塊作用域中,但內(nèi)部的this都指向window
原因:函數(shù)直接調(diào)用,會做默認(rèn)綁定,可類比為 fn.call(undefined),call 第一個參數(shù)是null或undefined,那么 this 將指向全局對象
常見面試題
示例1:
var a = 3; function c() { alert(a); //3 } (function () { var a = 4; c(); })();
示例2:
var name = "123"; var obj = { name: "456", print: function () { function a() { console.log(this.name); //123 } a(); }, }; obj.print();
無論面試題設(shè)計的多花里胡哨,只要記住 普通函數(shù)直接調(diào)用,默認(rèn)綁定,this指向全局 便可知道函數(shù)內(nèi)部this指向window
2. 隱式綁定
如果函數(shù)調(diào)用時,前面存在調(diào)用它的對象,那么this就會隱式綁定到這個對象上
let obj = { name: "123", fn: function () { console.log(this.name); //123 }, }; obj.fn();
如果函數(shù)調(diào)用前存在多個對象,this指向距離調(diào)用自己最近的對象
let obj = { name: "123", o: { name: "456", func: function () { console.log(this.name); }, }, }; obj.o.func(); //456
隱式丟失:通過變量賦值將對象中的函數(shù)變成普通函數(shù)
var name = "1"; let obj = { name: "2", fn: function () { console.log(this.name); }, }; let fn1 = obj.fn; fn1(); //1
fn1 直接調(diào)用,默認(rèn)綁定,this指向全局
3. 顯示綁定
顯示綁定:通過call、apply以及bind方法改變this的行為
let obj1 = { name: "1", }; let obj2 = { name: "2", }; let obj3 = { name: "4", }; var name = "3"; function fn() { console.log(this.name); } fn(); //3 默認(rèn)綁定,this指向全局 fn.call(obj1); //1 this指向obj1 fn.apply(obj2); //2 this指向obj2 fn.bind(obj3)(); //4 this指向obj3
拓展:call、apply、bind 相同點與不同點
相同點:改變this的指向
不同點:
call 第二個參數(shù)傳入一個參數(shù)列表
apply 第二個參數(shù)傳入一個參數(shù)數(shù)組
bind 第二個參數(shù)傳入一個參數(shù)列表,返回一個函數(shù),不會立即執(zhí)行
4. new 綁定
this指向生成的新對象
function Person(name, age) { this.name = name; this.age = age; } const p1 = new Person("1", 20); console.log(p1); // {name:'1', age:20}
5. 箭頭函數(shù)的this
默認(rèn)綁定外層 this
例1
var name = "1"; let obj = { name: "2", fn: function () { setTimeout(function () { console.log(this.name); //1 }); }, }; obj.fn();
setTimeout實際是window.setTimeout,因此函數(shù)內(nèi)部this指向window,打印結(jié)果為1
例2
var name = "1"; let obj = { name: "2", fn: function () { setTimeout(() => { console.log(this.name); //2 }); }, }; obj.fn();
由于使用了箭頭函數(shù),默認(rèn)綁定外層this,this指向函數(shù)fn
fn由obj調(diào)用,this隱式綁定到obj,最后打印的結(jié)果為2
例3:
var name = "window"; var student = { name: "1", fn: function () { var fn2 = () => { console.log(this.name); }; fn2(); }, fn3: () => { console.log(this.name); }, }; student.fn(); // '1' student.fn3(); // 'window'
- student.fn() 內(nèi)部執(zhí)行的是函數(shù)fn2,由于fn2是直接調(diào)用,默認(rèn)綁定到window上,但由于fn2是箭頭函數(shù),綁定外一層this,所以this指向函數(shù)fn,fn由student對象調(diào)用,因此最終this指向student
- student.fn3() 隱式綁定this指向student,由于fn3是箭頭函數(shù),默認(rèn)綁定外一層的this,最終this指向window
例4:防抖函數(shù)
function debounce(fn, delay) { let timer = null; return function () { clearTimeout(timer); timer = setTimeout(() => { //誰調(diào)用,this指向誰 fn.apply(this, arguments); }, delay || 1000); }; } function fn() { console.log(this); //document } document.addEventListener("click", debounce(fn));
setTimeout函數(shù)中的this默認(rèn)指向window,因為是箭頭函數(shù),默認(rèn)綁定外層this,因此this指向匿名函數(shù),匿名函數(shù)由document調(diào)用,所以this指向document。再通過apply將函數(shù)fn的this綁定到document上,因此打印出document
6. 優(yōu)先級
顯式綁定(bind>call/apply) > 隱式綁定 > 默認(rèn)綁定
1. 隱式綁定 > 默認(rèn)綁定
function bar() { console.log(this); //info } const info = { bar: bar, }; info.bar();
2. 顯示綁定 > 隱式綁定
var fullName = "global"; const info = { fullName: "1", getName: function () { console.log(this.fullName); }, }; info.getName.call(null); //global
3. bind > apply/call
function bar() { console.log(this); //{age: 1} } bar.bind({ age: 1 }).call({ age: 2 });
函數(shù)中的this綁定在 { age: 1 } 上,即使后面又使用了call綁定
7. 總結(jié)
1. 普通函數(shù),this的值取決于函數(shù)被調(diào)用的方式,分為默認(rèn)綁定,隱式綁定和顯示綁定
2. 箭頭函數(shù),默認(rèn)綁定外層this
到此這篇關(guān)于一文詳解JavaScript中this指向的問題的文章就介紹到這了,更多相關(guān)JavaScript this指向內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
javascript實現(xiàn)表格排序 編輯 拖拽 縮放
這篇文章主要介紹了javascript實現(xiàn)表格排序 編輯 拖拽 縮放的方法,效果非常不錯,只是兼容性還有些問題,有待優(yōu)化。2015-01-01淺談js之字面量、對象字面量的訪問、關(guān)鍵字in的用法
下面小編就為大家?guī)硪黄獪\談js之字面量、對象字面量的訪問、關(guān)鍵字in的用法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-11-11JS封裝的三級聯(lián)動菜單(使用時只需要一行js代碼)
在實際的項目開發(fā)中,我們經(jīng)常需要三級聯(lián)動,比如省市區(qū)的選擇,商品的三級分類的選擇等等。這篇文章主要介紹了JS封裝的三級聯(lián)動菜單(使用時只需要一行js代碼)的相關(guān)資料,需要的朋友可以參考下2016-10-10JS構(gòu)建頁面的DOM節(jié)點結(jié)構(gòu)的實現(xiàn)代碼
本來想用json格式的,可是要么有重復(fù),要么得嵌套,所以改用對象嵌套數(shù)組2011-12-12