javascript之this辨析

对于this,理解一直都不透彻,前前后后也看了一些技术书,以后相关博客,总算是想要总结点什么了。

this在不同的上下文环境指代不同的对象,与声明环境无关,与运行环境有关

  • this 指向全局对象window(在服务器端指向global)
var name = 'jack'
function sayName () {
    console.log(this.name)
}
sayName() // jack
  • this 指向当前的调用对象
// 第一种情况,作为对象方法的调用
function sayName () {
    console.log(this.name)
}
var o = {}
o.name = 'jack'
o.sayName = sayName
o.sayName() // jack
// 第二种情况作为构造函数调用时,this指向新创建的对象
1. 简单的场景
function Test () {
    this.x = 1
}
var o = new Test()
o.x //1


2. 为表明this不是全局对象,做一下修改
var x = 0
function Test () {
    this.x = 1
}
var o = new Test()
o.x // 1


3. 稍微复杂的场景
function Person(name){
    this.name = name
}
person.prototype.sayName = function () {
    console.log(this.name)
}
var xiaoming  = new Person('xiaoming')
xioaming.sayName() // xiaoming
  • 使用apply 或 call 来进行绑定 apply或call 是调用函数的方法,他们第一个参数都相同,用于指定当前函数的调用对象
var name = 'rose'
function sayName () {
    console.log(this.name)
}
var o = {}
o.name = 'jack'
o.sayName = sayName
o.sayName.apply() //输出rose      没有指定绑定对象,默认指向全局对象
o.sayName.apply(o) //输出 jack    此时this代表对象o

疑难this辨析

// 下面的this指代什么
var name = "Bob";  
var nameObj ={  
    name : "Tom",  
    showName : function(){  
        alert(this.name);  
    },  
    waitShowName : function(){  
        setTimeout(this.showName, 1000);  
    }  
};  

nameObj.waitShowName();  // Bob

为了解决以上问题,我们可以先一步一步看以下this的指向

var person = {
    name: 'jack',
    sayName: function () {
        console.log(this.name)
    }
}
var anotherPerson = {
    name: 'rose',
    sayName: person.sayName
}
anotherPerson.sayName() // rose
// this关键字虽然是person.sayName种声明的,但是运行的时候是在anotherPerson.sayName,所以this指向anotherPerson,输出rose
var name = 'jack'
var o = {
    name: 'rose',
    sayName: function () {
        console.log(this.name)
    }
}
var sayName = o.sayName
sayName() // jack
// 此时可以理解为,sayName()是在全局作用域下执行的,所有this指向window,window.name === 'jack'
var name = 'willie'
var Jack = {
    name: 'jack',
    sayName: function () {
        console.log(this.name)
    }
}
var Rose = {
    name: 'rose',
    sayName: function () {
        var fun = Jack.sayName
        fun()
    }
}
Rose.sayName() // willie
// 这次情况跟上次不同的是,是在函数内部引用了其他的函数,此时的this由于没有绑定Rose,所以指向默认的绑定window

在浏览器中,setTimeout, setInterval,匿名函数执行时的当前对象都是全局对象window

var name = 'wille'
var o = {
    name: 'jack',
    sayName: function () {
        setTimeout(function () {console.log(this.name)}, 100)
    }
}
o.sayName() // wille

// 使用ES6的箭头函数改写上述代码,观察会产生什么情况
var name = 'wille'
var o = {
    name: 'jack',
    sayName: function () {
        setTimeout(() => {console.log(this.na)},100)
    }
}
o.sayName() //jack 
// 记住在setTimeout,setInterval,匿名函数中,如果使用箭头函数改写,this指向当前上下文环境,而不是全局对象。

思考题, 思考下列this指向什么,以及原因

1:
var obj = {
    say: function () {
        setTimeout(() => {
          console.log(this)
        }, 0)
    }
}
obj.say() //obj

2:
function test() {
    console.log(this)
}
test() // window(全局)

3:
var obj = {
    say: function () {
        function _say () {
            console.log(this)
        }
        return _say.bind(obj)
    }() //立即执行函数,此时obj还没有声明出来,故this还是默认的window
}
obj.say() // window(全局)

4:
var obj = {}
obj.say = function () {
    function _say () {
        console.log(this)
    }
    return _say.bind(obj)
}() // 立即执行函数,这次obj已经声明了出来,此时的this指向obj
obj.say() // obj 
5: 
var obj = {
    sayName: function () {
        console.log('outer', this)
        return function () {
            console.log('inner', this)
        }
    }() 
}
//匿名函数立即执行,this指向window,返回了一个匿名函数的声明
//此时内部的匿名函数没有执行,所以this不会指向全局window
obj.sayName() //outer -> window    inner -> obj
// 而在真正执行时,此时的obj.sayName()中的this指向了调用对象obj
// 以上obj声明的等价形式为
var obj = {
    sayName : function () {
        console.log('inner', this)
    }
}
obj.sayName() // obj
// 此时应该可以一眼看出,当通过obj调用sayName时,this指向当前调用对象obj
posted @ 2021-03-09 20:09  eastsae  阅读(70)  评论(0编辑  收藏  举报