1. 程式人生 > 實用技巧 >javascript this指向

javascript this指向

在一些筆試題和專案中經常會出現一些this指向的問題。特此記錄一下

this的預設指向

1.全域性環境下this指向window
console.log(this) //window
2.函式獨立呼叫,函式內部的this也指向window 3.被巢狀的函式獨立呼叫時,this預設指向了window
        function fn1(){
            console.log(this); //window
        }
        fn1() //fn1() === window.fn1(),所以指向了window
        var a = 1;
        
var obj = { a:2, foo:function(){ // 函式當作物件的方法來呼叫時候,this指向obj var a = 3; var that = this; console.log(that.a) //2 function test(){ console.log(this.a); //1 } test() } } obj.foo()
//獨立函式呼叫指向window
4.IIFE自執行函式(自執行函式預設指向window,跟函式內部呼叫一致)
        var a = 10;
        var obj = {
            a:2,
            foo:function(){
                console.log(this); //函式當作物件的方法來呼叫時候,this指向obj
                (function test(){
                    console.log(this.a);
                })()  
//自執行函式預設指向window,跟函式內部呼叫一致 } } obj.foo() // 10 var a = 10; var obj = { a:2, foo:function(){ console.log(this); //函式當作物件的方法來呼叫時候,this指向obj (function test(that){ console.log(that.a); })(this) //自執行函式預設指向window,跟函式內部呼叫一致 } } obj.foo() // 10
5.閉包:this預設指向了window
        var a = 0;
        var obj = {
            a:2,
            foo:function(){
                return function test(){
                    return this.a //閉包 :this預設指向了window
                }
            }
        }
        var bb = obj.foo()
        console.log(bb()) //0
            

6.隱式繫結

//當函式當作方法來呼叫,this指向了直接物件
function foo(){
    console.log(this.a)
}
var obj = {
    a:1,
    foo:foo,
    obj2:{
        a:2,
        foo:foo
    }
}
// foo()函式的直接物件是obj,this的指向指向了直接物件
obj.foo(); //1
obj.obj2.foo(); //2

7.隱式丟失

//隱式丟失就是指被隱式繫結的函式丟失了繫結物件,從而預設繫結到window //這種情況就是比較容易出錯卻又非常常見

一、隱式丟失:函式別名

var a = 0;
function foo(){
    console.log(this.a)
}
var obj = {
    a:1,
    foo:foo
}
// 把obj.foo()賦值給別名bar,造成隱式丟失的情況,因為只是把obj.foo()賦值了給了bar變數,而bar與obj物件毫無關係
var bar = obj.foo;
bar(); //0 
相當於
var a = 0;
var bar = function foo(){
    console.log(this.a)
}
bar()

二、引數傳遞

// 2.引數傳遞
var a = 0;
function foo(){
    console.log(this.a)
}
function bar(fn){
    fn()
}
var obj = {
    a:1,
    foo:foo
}
// 把obj.foo當作引數傳遞到bar函式中,有隱式的函式複製fn = obj.foo, 只是把foo函式賦值給了fn,而fn與obj物件毫無關係,所以當前foo函式內部的this指向了window
bar(obj.foo) //0
等價於
var a = 0;
function bar(fn){
    fn()
}
bar(function foo(){
    console.log(this.a);
})

三、內建函式

// 3.內建函式 setTimeout()和setInterval()第一個引數的回撥函式中的this預設指向了window,跟第二種情況是類似
var a = 0;
function foo(){
    console.log(this.a)
}
var obj = {
    a:1,
    foo:foo
}
setTimeout(obj.foo,1000) //0 window

四、間接呼叫

// 4。間接呼叫
function foo(){
    console.log(this.a)
}
var a = 0;
var obj = {
    a:1,
    foo:foo
}
var p = {a:4}
// obj.foo(); //1
// // 立即呼叫
// // 將obj.foo函式物件賦值給p.foo函式,然後立即執行。相當與僅僅是foo()函式的立即呼叫,內部的this預設指向了window
// (p.foo = obj.foo)() //0
p.foo = obj.foo
// 將obj.foo賦值給p.foo函式,之後p.foo()函式再執行,其實是屬於p物件的函式的指向,this指向當前的p物件
p.foo() //4

五、其他情況

//5.其他情況(指向了window的特殊情況)
function foo(){
    console.log(this.a)
}
var a = 0;
var obj = {
    a:1,
    foo:foo
}
// 都是立即執行函式,指向window
(obj.foo = obj.foo)() //0
(false || obj.foo)()  //0
(1,obj.foo)() //0

8.顯示繫結

一、call() apply() bind()

// call() apply() bind() 把物件繫結到this上,叫做顯示繫結
var a = 0;
function foo(){
    console.log(this.a);
}
var obj = {
    a:2
}
foo() //0 window.foo()
foo.call(obj) //2
foo.apply(obj) //2
var fn = foo.bind(obj) //2 
fn()
二、硬繫結是顯示繫結的一個變種,使得this不能再被改變
var a = 0;
function foo(){
    console.log(this.a);
}
var obj = {
    a:2
}
var bar = function(){
    foo.call(obj)
}
setTimeout(bar,2000) //2
bar.call(window) //2

三、陣列的forEach(fn,物件)//map()filter()some()every()第二個引數改變this指向

// 陣列的forEach(fn,物件) //map() filter() some() every()第二個引數改變this指向
var id = 'window';
var obj = {
    id:'fn'
}
var arr = [1,2,3]
arr.forEach(function(el,index){
    console.log(el,index,this);
},obj) 
9.new繫結
function Fn() {
    //如果是new關鍵來執行函式,相當於建構函式來例項化物件,那麼內部的this指向了當前例項化的物件 
    console.log(this); //Fn {}
}
var fn = new Fn()
console.log(fn); //Fn {}

function Fn2(){
    // this還是指向了當前的物件
    console.log(this);
    // 使用return關鍵來返回物件的時候,例項化出來的物件是當前的返回物件
    return {
        name:'zhen'
    }
}
var fn2 =new Fn2() //Fn2{}
console.log(fn2) // {name: "zhen"}

var Person ={
    fav:function(){
        return this
    }
}
var p = new Person.fav();
console.log(p); //fav {}
console.log(p===Person.fav); //false
// 例項化出來的物件內部的屬性constructor屬性指向了當前的建構函式
console.log(p.__proto__.constructor === Person.fav);

10.嚴格模式下this指向

//1.獨立呼叫的函式內部的this指向了undefined
    function fn(){
        'use strict'
        console.log(this);
    }
    fn() //undefined
    //2.嚴格模式下,函式apply()和call()內部this始終是他們的第一個引數
    var color = 'red';
    function showColor(){
        'use strict'
        console.log(this.color);
    }
    showColor.call(undefined)