上篇文章this全面解析(一)中,咱们说了几个常见的错误认识。javascript
接下来,咱们来看看this究竟是一种什么样的机制java
this是运行时绑定,并非在编译时,上下文取决于函数调用时的各类条件。this绑定和函数的声明位置没有任何关系,只取决于函数的调用方式。编程
调用位置是函数在代码中被调用的位置(不是声明的位置)。函数
通常来讲,寻找调用位置就是找“函数被调用的位置”,但这并不一直是一件简单事,有些时候,编程模式会隐藏真正的调用位置。oop
不过咱们仍是有办法的!咱们能够经过分析调用栈(为了达到当前执行位置所调用的全部函数),那么咱们关心的,就是当前执行函数的前一个调用中。post
function baz() {
//当前调用栈:baz
//调用位置是全局做用域
console.log('baz');
bar(); //bar 的调用位置
}
function bar() {
//当前调用栈 baz--> bar
//所以当前调用位置在 baz 中
console.log('bar');
foo(); // foo的调用位置
}
function foo() {
//当前调用栈 baz-> bar ->foo
//当前调用位置在 bar 中
console.log('foo');
}
baz(); //baz调用位置
复制代码
其实,函数的调用栈也能够被想象成一个函数调用链~ui
独立函数调用(没法应用其余规则时,默认规则就是它了!)this
看这段代码spa
function foo() {
console.log(this.a);
}
var a = 1;
foo(); //2
复制代码
首先,咱们须要明白一个知识点:声明在全局做用域中的变量就是全局对象的一个同名属性,本质是一个东西,不是复制获得的code
当咱们调用foo,this.a 被解析成 全局变量a ,调用函数应用了this的默认绑定,this指向全局对象。
不过这里有一点
虽然this的绑定规则彻底取决于调用位置,可是只有 foo() 运行在 非严格模式下,默认绑定才会绑定到全局,严格模式下,与foo()的调用位置无关。
考虑调用位置,是否有上下文对象。
function foo(){
console.log( this.a );
}
var obj = {
a: 2,
foo: foo
}
obj.foo(); //2
复制代码
咱们先来看 foo() 的声明方式,不管是直接在obj中定义仍是先定义,再添加为引用属性,这个函数严格来讲都不属于obj对象。
可是,调用位置会使用obj上下文来引用函数,因此,你能够说,调用obj对象时,拥有或者包含它。调用foo()时,this被绑定到obj。this.a 和 obj.a 是同样的。
对象属性引用链中,只有最后一层影响调用位置
function foo() {
console.log( this.a );
}
var obj2 = {
a: 42,
foo: foo
}
var obj1 = {
a: 2,
obj2: obj2
}
obj1.obj2.foo(); //42
复制代码
function foo() {
console.log( this.a );
}
var obj = {
a: 2,
foo: foo
};
var bar = obj.foo; // 函数别名!
var a = "oops, global"; // a 是全局对象的属性 bar(); // "oops, global"
复制代码
虽然,bar是obj.foo的一个引用,实际上,引用的是foo函数自己!因此此时 bar() 是一个不带任何修饰的函数调用。
function foo(){
console.log( this.a );
}
function doFoo(fn) {
fn(); //调用位置
}
var obj = {
a: 2,
foo: foo
}
var a = "global";
doFoo( obj.foo ); //global
复制代码
参数传递其实就是一种隐式赋值,所以咱们传入函数时也会被隐式赋值,因此结果和上一 个例子同样。
下篇文章将介绍:显式绑定和new绑定两种方式。