this-作用域链-上下文-执行上下文
(以下不考虑严格模式)
this
1、普通函数的this:
默认绑定全局对象 或者 指向调用者
对象属性获取this的原则: It’s trying to get the [[Base]] property of the reference (which is e.g. refObj, when applied to refObj.func; or foo.bar when applied to foo.bar.baz).
手动绑定this
名称 | 缩写 |
---|---|
call、apply | .call(obj); .apply(obj); |
bind | 调用f.bind(someObject)会创建一个与f具有相同函数体和作用域的函数 ,this将永久地被绑定到了bind的第一个参数 |
function f(){
return this.a;
}
var h = f.bind({a:'yoo'}); // bind this永久生效,传值还可以正常传递
console.log(h());
2、箭头函数的this:
名称 | 缩写 |
---|---|
非对象属性 | 该箭头函数在定义时,所处执行文中 迭代向上寻找的最近上层环境的this |
对象的属性 | globalThis |
词法作用域只由函数被声明时所处的位置决定
When calling a function as a property of an object, it is called with the this binding set to globalThis.
var c=6
function refObj(){
let c=9;
let a= {
e:{
d:()=>this.c,
},
}
console.log(a.e.d())
}
refObj() //6
以下为旧版记录
1、
var globalObject = this;
var foo = (() => this);
console.log(foo() === globalObject); // true
2、
var obj = {
bar: function() {
var x = (() => this);
return x;
}
};
// 作为 obj 对象的一个方法来调用 bar,把它的 this 绑定到 obj。
// 将返回的函数的引用赋值给 fn。
var fn = obj.bar();
console.log(fn() === obj); // true
// 只是引用 obj 的方法,
var fn2 = obj.bar;
console.log(fn2()() == window); // true
c=1;
let a={b:function(){return ()=>this.c},c:3}
a.b()()//3
c=1;
let a={d:{b:function(){return ()=>this.c},c:3},c:5}
a.d.b()()//3
c=1;
let a={d:{b: ()=>this.c,c:3},c:5}
a.d.b()//1
c=1;
let a={f:{d:{b: ()=>this.c,c:3},c:5},c:9}
a.f.d.b()//1
构造函数的this不遵循对象的this
var a=999;
const refObj = {
e:{
c:function(){
console.log(this.k);
console.log(this);
},
k:this.a
},
b:2
};
refObj.e.c()
// 999
// {k: 999, c: ƒ}
词法作用域
作用域链
在编译阶段,词法作用域就已确立(这是建立在无eval和with等动态添加代码的情况下),此时确立了用于函数调用时的变量标识。故而函数寻找变量是在作用域链中寻找,而不是根据调用时的嵌套关系,与调用无关,与定义有关。如下代码:
var b = 1;
function aaa() {
var a = 2;
console.log(c)//Uncaught ReferenceError: c is not defined
}
function bbb() {
var c = 3;
console.log("这里可以访问到b,b为", b)//这里可以访问到b,b为 1
aaa();
//这里实际在bbb这个词法环境中并不能找到aaa这个函数
//而是到他的作用域链中寻找,于是找到了外层环境的window
}
bbb()
即使调用是嵌套的,也不能在aaa中获取到bbb的变量。明显可以看出作用域不是在调用时确定的,其实是在编译阶段,上下文对象就已经确立了,在函数调用时,将调用上下文,其中包含了作用域链。
var b = 1;
function bbb() {
function aaa() {
var a = 2;
console.log(c)//3
}
var c = 3;
console.log("这里可以访问到b,b为", b)//这里可以访问到b,b为 1
aaa();
}
bbb()
执行上下文
在编译阶段执行上下文就已确立,包括包含的作用域链。
执行上下文上下文包含了:变量对象、this以及作用域链
进入执行上下文时,VO的初始化过程具体如下:
-
函数的形参(当进入函数执行上下文时) 变量对象的一个属性,其属性名就是形参的名字,其值就是实参的值;对于没有传递的参数,其值为undefined
-
函数声明(FunctionDeclaration, FD) 变量对象的一个属性,其属性名和值都是函数对象创建出来的;如果变量对象已经包含了相同名字的属性,则替换它的值
-
变量声明(var,VariableDeclaration) 变量对象的一个属性,其属性名即为变量名,其值为undefined;如果变量名和已经声明的函数名或者函数的参数名相同,则不会影响已经存在的属性。
当执行到某一函数时,将该执行上下文加入调用栈,将激活活动对象(AO)。 AO是在进入函数的执行上下文时创建的,并为该对象初始化一个arguments属性,该属性的值为Arguments对象,(变量对象+arguments)。
推荐:https://leohxj.gitbooks.io/front-end-database/content/javascript-advance/scope-chain.html