文章原地址 https://www.jianshu.com/p/59be7936c345
this指向问题
var obj = {
foo: function () {
console.log(this.bar)
},
bar: 1
};
var foo = obj.foo;
var bar = 2;
// 写法一
obj.foo(); //1
// 写法二
foo(); //2
虽然obj.foo和foo指向同一个函数,但执行结果却不一样,这种差异的原因就是因为在函数内部使用了this关键字,很多教科书会告诉你,this是函数运行时所在的环境,对于obj.foo()来说,foo运行在obj环境,所以this指向obj,对于foo()来说,foo()运行在全局环境,所以this指向全局环境,所以,两者运行结果不一样
下面思考一下:为什么obj.foo()就是在obj环境执行,而一旦var foo = obj.foo; foo()就变成了在全局环境中执行,本文就解释一下javascript这样处理的原理
内存的数据结构
javascript语言之所以有this的设计,跟内存里面的数据有关系
var obj = {foo: 5}
上面的代码将一个对象赋值给变量obj,js引擎会先在内存里面,生成一个对象{foo: 5},然后把这个对象的内存地址赋值给变量obj,也就是说,变量obj是一个地址,后面如果要读obj.foo,引擎先从obj拿到内存地址,然后再从该地址中读取原始的对象,返回他的foo属性
原始的对象以字典结构保存,每一个属性名都对应一个属性描述对象,例如:上面foo属性,实际上是以这种形式保存的
{
foo: {
[[value]]: 5,
[[writable]]: true,
[[enumerable]]: true,
[[configurable]]: true
}
}
注意: foo属性的值保存在属性描述对象的value属性里面
函数
var obj1 = {
foo: function () {
console.log(111)
}
}
这时,引擎会将函数单独保存在内存中,然后将函数的地址赋值给foo属性的value属性 //例如:
{
foo: {[[value]]: 函数的地址}
}
由于函数是一个单独的值,所以他可以在不同的环境(上下文)执行
var f = {
name: '王淼',
foo: function() {
console.log(this.name)
}
}
f.foo()
var obj = f.foo;
var name = 'nihao'
obj()
所以说虽然f.foo和obj指向同一个函数,但执行的结果不同
环境变量
js 允许在函数体内部,引用当前环境的其他变量
var f = function () {
console.log(x)
}
上面代码中引用了变量x,该变量由运行环境提供,那么问题来了,由于函数可以在不同的运行环境执行,所以需要一种机制,能够在函数体内部获得当前的执行环境,所以,this就出现了,他的设计目的就是在函数体内部,指代当前的运行环境
var f = function () {
console.log(this.x)
}
上面代码中。函数体内的this.x就是指当前运行环境的x
var x = 1;
var obj = {f: f,x: 2}
//单独执行
f(); //1
//环境执行
obj.f() //2
上面代码中,函数f在全局环境执行,this.x指向全局环境的x
相当于在, 内存中存储函数,将函数的地址赋值给f变量,变量f指向函数本身,所以在全局环境下执行,而{f: f ,x: 2}会存到内存中,将对象的地址赋值给obj,所以obj.f是通过obj找到f,所以就是在obj环境下执行