this是执行环境对象的属性,指向执行环境运行时所在的对象;
this与可执行代码的类型直接相关,其值在进入执行环境阶段肯定,并且在执行过程当中保持不变;javascript
在全局执行环境中,this老是执行全局对象自己;前端
//显式的定义全局对象的属性 this.a=10; console.log(a); //隐式的定义全局对象的属性 b=20; console.log(b); //经过变量声明间接的定义全局对象的属性 var c=30; console.log(this.c);//30
在函数执行环境中,this值不是静态绑定到函数的;java
this值是在进入执行环境时肯定的,指向调用函数时的执行环境,对于同一函数经过不一样方式调用其this指向不一样的对象;数组
this值肯定以后,在代码执行阶段其值是不变的,this值不是变量因此不能为其分配新值;app
var foo = { x:10 }; var bar={ x:20, test: function(){ console.log( this ); // bar, { x: 20, test: [Function] } console.log( this.x ); // 20 } }; bar.test(); foo.test=bar.test; foo.test(); //this指向foo, { x: 10, test: [Function] }
this是由激活函数执行环境的caller提供, 好比调用函数的父级执行环境,但决定this值的唯一因素是调用表达式的形式,即调用函数的语法形式 ;函数
通常会说this值取决于函数的定义方式,全局环境中的函数this值指向全局对象,做为对象的方法的函数this指向该对象,这种说法是错误的;this
var variable = 22; function foo(){ var variable = 11; console.log(this.variable); } console.log( "here" ); foo(); //22 console.log( foo === foo.prototype.constructor );// true foo.prototype.constructor(); // undefined
var foo={ bar:function(){ console.log(this===foo); } }; foo.bar(); // true var test=foo.bar; console.log(test === foo.bar); // true test(); // false
引用类型的值能够表示为包含两个属性的对象:prototype
var valueOfReferenceType={ base:<base object>, propertyName: <property name> };
引用类型的值只适用于标识符解析和属性访问两种状况:code
标识符解析对象
标识符解析返回的值是一个引用类型的值;
标识符包括变量名、函数名、函数的形式参数名和全局对象中的unqualified的属性名;
var foo=10; function bar(){};
以上代码对应的引用类型以下所示:
// 变量 foo var fooReference={ base:global, propertyName:"foo" } // 函数 bar var barReference={ base:global, propertyName:"bar" }
为了从引用类型的值获得对真正的值,在内部使用GetValue()
方法,用伪代码表示以下:
内部方法[[Get]]
用于从对象获取指定属性,包括从原型链继承而来的属性;
function GetValue(value){ //非引用类型的值直接返回 if( Type(value) != Reference){ return value; } //获取值所属的对象 var base=GetBase( value ); if( base===null ){ throw new ReferenceError; } //返回从值所属的对象获取的属性值,经过 [[Get]] 方法 var propertyName = GetPropertyName( value ); return base.[[Get]]( propertyName ); }
获取fooReference
和barReference
的值:
GetValue(fooReference); // 10 GetValue(barReference); // 函数对象 bar
属性访问
属性访问分为点访问法和方括号访问法;
点访问法中的属性必须是标识符;
foo.bar(); foo["bar"]();
函数执行环境中的this由激活函数执行环境的caller提供,但决定this值的唯一因素是调用表达式的形式,即调用函数的语法形式;
若是表示函数调用的圆括号的左侧是一个引用类型的值,则函数中的this指向该引用类型值的base对象;
标识符:
function foo(){ return this; } foo(); // window // 标识符foo的引用类型表示 var fooReference={ base: global, propertyName: "foo" } foo.prototype.constructor(); // foo.prototype // foo.prototype.constructor是属性 var fooPrototypeConstructorReference = { base:foo.prototype, propertyName:"constructor" }
属性访问:
var foo={ bar:function(){ return this; } }; foo.bar(); // foo //属性foo.bar的引用类型表示 var fooBarReference={ base: foo, propertyName: "bar" }; //经过不一样形式的调用表达式调用同一函数: var test = foo.bar; test(); // window // test是标识符 var testReference={ base:global, propertyName:"test" }
当表示函数调用的圆括号的左侧不是引用类型的值时,this老是设置为null;
由于将this设置为null值没有意义,因此隐式的将其转换为全局对象;
在ES5的严格模式下this值再也不强迫转换为全局对象,而是设置为undefined;
(function(){ console.log(this); // window })();
var foo={ bar: function(){ console.log(this); } }; foo.bar(); // foo (foo.bar)(); //foo //第一个圆括号是一个组运算符,从引用类型获取值的GetValue()方法不适用与该运算符(why),其返回值仍然是引用类型 (foo.bar=foo.bar)(); //赋值运算符, 使用GetValue()方法进行求值,返回值是一个函数对象,因此null (false || foo.bar)(); // 返回foo.bar表示的值,函数对象,因此null (foo.bar,foo.bar)(); // 返回函数对象,因此null
当引用类型值的base对象是活动对象时,this值将指向null,并转换为全局对象;
function foo(){ function bar(){ console.log(this); // gloabl } bar(); //等价于AO.bar(), 但AO做为base对象返回null }
经过with调用函数时,with对象被添加到做用域链最前端,屏蔽外层函数的活动对象或者全局对象,函数中的this老是指向with对象;
var x=10; with({ foo:function(){ console.log(this.x) }, x:20 }){ foo(); // 20 }
foo的引用类型:
var fooReference={ base:__withObject, propertyName:"foo" };
ES3中调用catch语句传入的参数函数时,函数中的this指向catch对象,而不是全局对象或活动对象;
这被认为是一个bug, 在ES5中获得修正,this将指向全局对象;
try{ throw function(){ console.log(this); }; }catch(e){ e(); } var eReference={ base:global, propertyName:"e" };
在递归的调用命名函数表达式时,第一次调用中base对象是外层函数的活动对象或者全局对象,在以后的递归调用中base对象应该是存储函数表达式名的特殊对象,但实际上this值老是指向全局对象;
(function foo(bar){ console.log(this); !bar && foo(1); })() //window window
在构造函数内this老是指向新建立的对象;
new操做符调用构造函数的内部方法[[construct]]
建立新对象,对象建立以后在构造函数上调用[[call]]
方法,this指定为新建的对象,初始化新对象;
function Foo(){ console.log(this); this.x=10; } var foo=new Foo(); console.log(foo.x);
在Function.prototype
上定义了apply()
和call()
方法用于手动的指定函数调用中的this;
call()
和apply()
的第一个参数是在函数执行环境中使用的this值, 其余参数传入调用的函数;
call接受任意数量的参数,apply数组做为参数;
var variable = 1; function act(arg) { console.log(this.variable); console.log(arg); } act(2); // 1, 2 act.call({variable : 3}, 4); // 3, 4 act.apply({variable : 5}, [6]); // 5, 6