我希望找到一个清晰的解释,“this”关键字的作用是什么,以及如何正确使用它。
它似乎表现得很奇怪,我不完全明白为什么。
this
如何工作,应该在什么情况下使用?
我希望找到一个清晰的解释,“this”关键字的作用是什么,以及如何正确使用它。
它似乎表现得很奇怪,我不完全明白为什么。
this
如何工作,应该在什么情况下使用?
this
是JavaScript中的一个关键字,它是执行上下文的属性。它在函数和构造函数中的主要用途。
this
的规则非常简单(如果你遵循最佳实践)。
this
在规范中的技术描述ECMAScript标准通过抽象操作(缩写为AO) ResolveThisBinding来定义this
:
[AO] ResolveThisBinding(…)使用运行时执行上下文的LexicalEnvironment确定关键字
this
的绑定。[步骤]:
- 让envRec成为GetThisEnvironment()。
- 返回?envRec.GetThisBinding()。
全局环境记录, 模块环境记录和函数环境记录各自都有自己的GetThisBinding方法。
GetThisEnvironment AO查找当前运行执行上下文的词法环境,并找到最近的具有this绑定(即HasThisBinding返回true)的祖先环境记录(通过迭代访问它们的[[OuterEnv]]属性)。此过程以三种环境记录类型之一结束。
this
的值通常取决于代码是否处于严格模式。
GetThisBinding的返回值反映了当前执行上下文中this
的值,因此每当建立新的执行上下文时,this
就会解析为一个不同的值。这也可能发生在修改当前执行上下文时。以下子节列出了可以发生这种情况的五种情况。
您可以将代码示例放入AST explorer中,以遵循规范详细信息。
这是在顶层评估的脚本代码,例如直接在<script>
内部:
<script>
// Global context
console.log(this); // Logs global object.
setTimeout(function(){
console.log("Not global context");
});
</script>
this
会导致GetThisBinding执行以下步骤:
全局环境记录的[[GlobalThisValue]]属性始终设置为由InitializeHostDefinedRealm步骤产生的主机定义的全局对象,可以通过来自全局环境记录envRec的GetThisBinding具体方法[...][执行如下]:
- 返回envRec.[[GlobalThisValue]]。
globalThis
(Web上的window
,Node.js上的global
;MDN文档)访问。
<script type="module">
内,而不是简单的<script>
。this
会导致 GetThisBinding 执行以下步骤:
在模块中,模块环境记录的 GetThisBinding 具体方法 [...] [执行如下操作]:
- 返回 undefined。
this
的值始终为 undefined
在全局上下文中。模块隐式地处于严格模式。
eval
调用: direct 和 indirect。自 ECMAScript 第5版以来存在此区别。
eval
调用通常看起来像eval(
…);
或者(eval)(
…);
(或者((eval))(
…);
等)。1只有当调用表达式符合一种狭窄的模式时才是直接的。2eval
调用涉及以任何其他方式调用函数引用eval
。它可以是eval?.(
…)
,(
…, eval)(
…)
,window.eval(
…)
,eval.call(
…,
…)
等。给定const aliasEval1 = eval; window.aliasEval2 = eval;
,它也可以是aliasEval1(
…)
,aliasEval2(
…)
。另外,如果给定const originalEval = eval; window.eval = (x) => originalEval(x);
,调用eval(
…)
也将是间接的。请参考chuckj针对“(1, eval)('this') vs eval('this') in JavaScript?”的回答和Dmitry Soshnikov的ECMA-262-5详解-第2章:严格模式(已存档),了解何时可以使用间接的eval()
调用。
PerformEval执行eval
代码。它创建一个新的声明性环境记录作为其词法环境,在那里GetThisEnvironment从中获取this
值。
然后,如果this
出现在eval
代码中,则会调用由GetThisEnvironment找到的环境记录的GetThisBinding方法,并返回其值。
创建的声明性环境记录取决于eval
调用是直接还是间接的:
eval
中,它将基于当前运行执行上下文的词法环境。eval
中,它将基于执行间接eval
的Realm Record的[[GlobalEnv]]属性(一个全局环境记录)。这意味着:
eval
中,this
值不会改变;它取自调用eval
的词法作用域。eval
中,this
值是全局对象(globalThis
)。new Function
呢? — new Function
类似于eval
,但它不会立即调用代码;它创建一个函数。这里没有应用this绑定,除非函数被调用,在下一小节中将会解释。
输入函数代码是在调用函数时发生的。
有四种语法类别可以调用函数。
此外,函数环境记录中还有[[ThisValue]]字段:函数环境记录是一个声明性环境记录,用于表示函数的顶级范围,并提供
this
绑定(如果函数不是一个ArrowFunction)。如果一个函数不是ArrowFunction函数并且引用了super
,它的函数环境记录还包含用于在函数内部执行super
方法调用的状态。
这是用于此函数调用的
this
值。
NewFunctionEnvironment 调用还设置了函数环境的 [[ThisBindingStatus]] 属性。
[[Call]] 也调用 OrdinaryCallBindThis,其中适当的 thisArgument 基于:
一旦确定,最终对新创建的函数环境记录的 BindThisValue 方法进行的调用实际上将 [[ThisValue]] 字段设置为 thisArgument。
最后,这个字段就是 函数环境记录的 GetThisBinding AO 从中获取 this
的值的地方:
函数环境记录中的GetThisBinding具体方法envRec[...]执行以下操作:
[...]
3. 返回envRec.[[ThisValue]]。
再次强调,确定this值的方式取决于许多因素;这只是一个概述。在了解这个技术背景后,让我们来看看所有具体的例子。
当评估箭头函数时,函数对象的[[ThisMode]]内部插槽设置为"词法"在OrdinaryFunctionCreate中。
在OrdinaryCallBindThis中,它接受一个函数F:
- 让thisMode成为F。[[ThisMode]]。
- 如果thisMode是lexical,则返回NormalCompletion(
undefined
)。 [...]
这意味着绑定this的其余算法被跳过。箭头函数不会绑定自己的this值。
因此,箭头函数中的this
是什么?回顾ResolveThisBinding和GetThisEnvironment,HasThisBinding方法明确返回false。
因此,外部环境将被迭代查找。该过程将在具有this绑定的三个环境之一中结束。函数环境记录的HasThisBinding具体方法envRec [...] [这样做]:
- 如果envRec。[[ThisBindingStatus]]为lexical,则返回false;否则,返回true。
this
来自箭头函数的词法范围,或者换句话说(来自Arrow function vs function declaration / expressions: Are they equivalent / exchangeable?):
箭头函数没有自己的
this
[...]绑定。相反,[该标识符将]像其他变量一样在词法范围内解析。这意味着在箭头函数内部,this
[指的是]箭头函数所在环境中定义的this
的值(即在箭头函数“外部”)。
在普通函数(function
、方法)中,this
由函数被调用的方式确定。
这就是这些“语法变体”有用的地方。
考虑包含一个函数的对象:
const refObj = {
func: function(){
console.log(this);
}
};
或者:
const refObj = {
func(){
console.log(this);
}
};
func
内部的this
值将为refObj
。1
refObj.func()
refObj["func"]()
refObj?.func()
refObj.func?.()
refObj.func``
this
的值。这是由上面链接的评估步骤解释的; 例如,在refObj.func()
(或refObj["func"]()
)中,CallMemberExpression是整个表达式refObj.func()
,其中包括MemberExpressionrefObj.func
和Arguments ()
。refObj.func
和refObj
也各自扮演三种角色:
refObj.func
是可调用的函数对象;对应的引用用于确定this
绑定。?.()
、``
或()
之前的所有内容。
EvaluateCall使用IsPropertyReference来确定它是否是对象的属性,从语法上讲。 它试图获取引用的[[Base]]属性(例如,当应用于refObj.func
时为refObj
;或者当应用于foo.bar.baz
时为foo.bar
)。 如果它被写成属性,则GetThisValue将获取此[[Base]]属性并将其用作this值。
注意:Getters / Setters与方法相同,关于this
的处理方式。简单属性不会影响执行上下文,例如在此处,this
位于全局范围内:
const o = {
a: 1,
b: this.a, // Is `globalThis.a`.
[this.a]: 2 // Refers to `globalThis.a`.
};
with
的调用没有基础引用的调用通常是一个不作为属性调用的函数。例如:
func(); // As opposed to `refObj.func();`.
j
:根据规范,您会注意到j
只能返回函数对象(值)本身,而不是引用记录。因此,基础引用refObj
丢失了。const g = (f) => f(); // No base ref.
const h = refObj.func;
const j = () => refObj.func;
g(refObj.func);
h(); // No base ref.
j()(); // No base ref.
(0, refObj.func)(); // Another common pattern to remove the base ref.
EvaluateCall在这里使用undefined作为thisValue调用Call,这会影响OrdinaryCallBindThis(F: 函数对象; thisArgument: 传递给Call的thisValue):
- 令thisMode为F.[[ThisMode]]。
[...]
- 如果thisMode是strict,则让thisValue为thisArgument。
- 否则,
[...]
注意:第5步在严格模式下将this
的实际值设置为提供的thisArgument——在这种情况下为undefined
。在“松散模式”下,未定义或null的thisArgument导致this
成为全局this值。
这就是未定义的< em >thisValue< /em >可能来自的地方:< em >refEnv< /em >.WithBaseObject()总是< strong >undefined< /strong >,除了在
- 让< em >refEnv< /em >成为< em >ref< /em >.[[Base]]。
- 断言:< em >refEnv< /em >是环境记录。
- 让< em >thisValue< /em >成为< em >refEnv< /em >.WithBaseObject()。
with< /code>
语句中。在这种情况下,< em >thisValue< /em >将成为绑定对象。
还有Symbol.unscopables< /code>
(MDN上的文档)来控制< code >with< /code >绑定行为。
总结一下,到目前为止:
function f1(){
console.log(this);
}
function f2(){
console.log(this);
}
function f3(){
console.log(this);
}
const o = {
f1,
f2,
[Symbol.unscopables]: {
f2: true
}
};
f1(); // Logs `globalThis`.
with(o){
f1(); // Logs `o`.
f2(); // `f2` is unscopable, so this logs `globalThis`.
f3(); // `f3` is not on `o`, so this logs `globalThis`.
}
并且:
"use strict";
function f(){
console.log(this);
}
f(); // Logs `undefined`.
// `with` statements are not allowed in strict-mode code.
请注意,在评估this
时,普通函数定义的位置并不重要。
.call
, .apply
, .bind
, thisArg和原始值
OrdinaryCallBindThis的第5步与第6.2步(规范中的6.b)相结合的另一个结果是,在“松散”模式下,原始的this值仅被强制转换为对象。
为了检查这一点,让我们介绍另一个源this值:覆盖this绑定的三个方法:4
Function.prototype.apply(thisArg, argArray)
Function.prototype.
{call
, bind
} (thisArg, ...args)
.bind
创建一个绑定函数,其this绑定设置为thisArg,并且不能再次更改。.call
和.apply
立即调用该函数,并将this绑定设置为thisArg。
.call
和.apply
直接映射到Call,使用指定的thisArg。.bind
使用BoundFunctionCreate创建一个绑定函数。这些函数有自己的[[Call]] method,该方法查找函数对象的[[BoundThis]]内部插槽。
设置自定义this值的示例:
function f(){
console.log(this);
}
const myObj = {},
g = f.bind(myObj),
h = (m) => m();
// All of these log `myObj`.
g();
f.bind(myObj)();
f.call(myObj);
h(g);
对于对象,在严格模式和非严格模式下是相同的。
现在,请尝试提供一个原始值:
function f(){
console.log(this);
}
const myString = "s",
g = f.bind(myString);
g(); // Logs `String { "s" }`.
f.call(myString); // Logs `String { "s" }`.
在非严格模式下,原始值会被强制转换为其包装对象形式。这与调用 Object("s")
或 new String("s")
时获得的对象相同。在严格模式下,您可以使用原始值:
"use strict";
function f(){
console.log(this);
}
const myString = "s",
g = f.bind(myString);
g(); // Logs `"s"`.
f.call(myString); // Logs `"s"`.
库使用这些方法,例如jQuery将this
设置为所选的DOM元素:
$("button").click(function(){
console.log(this); // Logs the clicked button.
});
构造函数、类和 new
使用 new
运算符调用函数作为构造函数时,EvaluateNew 调用 Construct,后者调用 [[Construct]] 方法。如果该函数是基础构造函数(即不是 class extends
…{
…}
),则将 thisArgument 设置为从构造函数的原型创建的新对象。在构造函数中设置的属性将最终出现在生成的实例对象上的 this
上。除非您显式返回自己的非原始值,否则会隐式返回 this
。
class
是 ECMAScript 2015 中引入的一种创建构造函数的新方法。
function Old(a){
this.p = a;
}
const o = new Old(1);
console.log(o); // Logs `Old { p: 1 }`.
class New{
constructor(a){
this.p = a;
}
}
const n = new New(1);
console.log(n); // Logs `New { p: 1 }`.
类定义隐式地处于严格模式中:
class A{
m1(){
return this;
}
m2(){
const m1 = this.m1;
console.log(m1());
}
}
new A().m2(); // Logs `undefined`.
super
new
关键字在派生类的使用上有例外,即class extends
…{
…}
,如上所述。派生类在调用时不会立即设置它们的this值;只有当通过一系列super
调用到达基类时才会这样做(在没有自己的constructor
的情况下隐式发生)。在调用super
之前使用this
是不允许的。
调用super
会使用调用的词法作用域(函数环境记录)的this值调用超级构造函数。GetThisValue对于super
调用有一个特殊规则。它使用BindThisValue将this
设置为该环境记录。
class DerivedNew extends New{
constructor(a, a2){
// Using `this` before `super` results in a ReferenceError.
super(a);
this.p2 = a2;
}
}
const n2 = new DerivedNew(1, 2);
console.log(n2); // Logs `DerivedNew { p: 1, p2: 2 }`.
5. 评估类字段
实例字段和静态字段在 ECMAScript 2022 中被引入。
当一个 class
被评估时,执行 ClassDefinitionEvaluation,修改 running execution context。对于每个 ClassElement:
- 如果字段是静态的,则
this
指的是类本身,
- 如果字段不是静态的,则
this
指的是实例。
私有字段(例如 #x
)和方法将添加到 PrivateEnvironment 中。
Static blocks 目前是一个 TC39 stage 3 proposal。静态块与静态字段和方法相同:其中的 this
指的是类本身。
请注意,在方法和 getter / setter 中,this
的工作方式与普通函数属性相同。
class Demo{
a = this;
b(){
return this;
}
static c = this;
static d(){
return this;
}
// Getters, setters, private modifiers are also possible.
}
const demo = new Demo;
console.log(demo.a, demo.b()); // Both log `demo`.
console.log(Demo.c, Demo.d()); // Both log `Demo`.
1: (o.f)()
相当于o.f()
; (f)()
相当于f()
。这在这篇2ality文章(存档)中有解释。特别看如何评估括号表达式。
2: 它必须是一个MemberExpression,不能是属性,必须具有完全匹配的[[ReferencedName]] "eval",并且必须是%eval%内部对象。
3: 每当规范中说“让ref成为评估X的结果”,那么X是一个表达式,你需要找到它的评估步骤。例如,评估MemberExpression或CallExpression的结果是其中一种这些算法。其中一些会导致Reference Record。
4: 还有其他几个本地和宿主方法允许提供this值,尤其是Array.prototype.map
、Array.prototype.forEach
等,它们接受thisArg作为第二个参数。任何人都可以制作自己的方法来更改this
,例如(func, thisArg) => func.bind(thisArg)
、(func, thisArg) => func.call(thisArg)
等。像往常一样,MDN提供了很好的文档。
只是为了好玩,用一些例子来测试你的理解
对于每个代码片段,请回答问题:“在标记行处this
的值是什么?为什么?”。
要显示答案,请单击灰色框。
-
if(true){
console.log(this); // What is `this` here?
}
globalThis
. The marked line is evaluated in the initial global execution context.
-
const obj = {};
function myFun(){
return { // What is `this` here?
"is obj": this === obj,
"is globalThis": this === globalThis
};
}
obj.method = myFun;
console.log(obj.method());
obj
. When calling a function as a property of an object, it is called with the this binding set to the base of the reference obj.method
, i.e. obj
.
-
const obj = {
myMethod: function(){
return { // What is `this` here?
"is obj": this === obj,
"is globalThis": this === globalThis
};
}
},
myFun = obj.myMethod;
console.log(myFun());
globalThis
. Since the function value myFun
/ obj.myMethod
is not called off of an object, as a property, the this binding will be globalThis
.
This is different from Python, in which accessing a method (obj.myMethod
) creates a bound method object.
-
const obj = {
myFun: () => ({ // What is `this` here?
"is obj": this === obj,
"is globalThis": this === globalThis
})
};
console.log(obj.myFun());
globalThis
. Arrow functions don’t create their own this binding. The lexical scope is the same as the initial global scope, so this
is globalThis
.
-
function myFun(){
console.log(this); // What is `this` here?
}
const obj = {
myMethod: function(){
eval("myFun()");
}
};
obj.myMethod();
globalThis
. When evaluating the direct eval call, this
is obj
. However, in the eval code, myFun
is not called off of an object, so the this binding is set to the global object.
-
function myFun() {
// What is `this` here?
return {
"is obj": this === obj,
"is globalThis": this === globalThis
};
}
const obj = {};
console.log(myFun.call(obj));
obj
. The line myFun.call(obj);
is invoking the special built-in function Function.prototype.call
, which accepts thisArg
as the first argument.
-
class MyCls{
arrow = () => ({ // What is `this` here?
"is MyCls": this === MyCls,
"is globalThis": this === globalThis,
"is instance": this instanceof MyCls
});
}
console.log(new MyCls().arrow());
It’s the instance of MyCls
. Arrow functions don’t change the this binding, so it comes from lexical scope. Therefore, this is exactly the same as with the class fields mentioned above, like a = this;
. Try changing it to static arrow
. Do you get the result you expect?
this
设置为事件的currentTarget
。这三个提案可以包含在未来中:绑定运算符::
,显式this,this
参数反射。DOM 0事件属性如onclick
也值得注意:JS代码隐式地包装在一个document
和一个点击元素的with
作用域中,导致混淆;this
是具有该属性的元素。 - Sebastian Simonthis
的每一个细节。但是在全局范围内,没有人真正需要this
,with
已经被弃用,不鼓励使用eval
,应该在任何地方都使用严格模式等等。所有剩下的就是obj.method()
调用带有function
或方法的method
时,将obj
作为this
传递;func()
调用func
而不带任何this
;.bind
、.call
和.apply
可以显式地绑定this
;箭头函数不会得到this
绑定。类:在静态事物中,this
指的是类本身,在非静态事物中,指的是正在创建的实例。就是这样。 - Sebastian Simon在 JavaScript 中,this
关键字与其他语言的行为不同。在面向对象的语言中,this
关键字引用类的当前实例。但在 JavaScript 中,this
的值由函数的调用上下文(context.function()
)和它被调用的位置决定。
1. 当在全局上下文中使用时
当你在全局上下文中使用 this
时,它会绑定到全局对象(在浏览器中是 window
)。
document.write(this); //[object Window]
当你在全局范围内定义的函数中使用this
时,this
仍然绑定到全局对象,因为该函数实际上是全局上下文的方法之一。
function f1()
{
return this;
}
document.write(f1()); //[object Window]
上述代码将f1
作为全局对象的方法定义,因此我们也可以在window
对象上调用它,如下所示:
function f()
{
return this;
}
document.write(window.f()); //[object Window]
2. 在对象方法中使用
当您在对象方法中使用this
关键字时,this
绑定到“直接”封闭对象。
var obj = {
name: "obj",
f: function () {
return this + ":" + this.name;
}
};
document.write(obj.f()); //[object Object]:obj
上面我用双引号括起来了单词“immediate”。这是为了表明,如果你将对象嵌套在另一个对象内部,那么this
将绑定到直接的父级。
var obj = {
name: "obj1",
nestedobj: {
name:"nestedobj",
f: function () {
return this + ":" + this.name;
}
}
}
document.write(obj.nestedobj.f()); //[object Object]:nestedobj
即使您将函数显式添加到对象作为方法,它仍然遵循上述规则,即this
仍然指向直接父对象。
var obj1 = {
name: "obj1",
}
function returnName() {
return this + ":" + this.name;
}
obj1.f = returnName; //add method to object
document.write(obj1.f()); //[object Object]:obj1
3. 当调用无上下文函数时
当您在没有任何上下文的情况下使用this
来调用函数(即不在任何对象上),它将绑定到全局对象(浏览器中的window
),即使该函数在对象内部定义。
var context = "global";
var obj = {
context: "object",
method: function () {
function f() {
var context = "function";
return this + ":" +this.context;
};
return f(); //invoked without context
}
};
document.write(obj.method()); //[object Window]:global
使用函数尝试所有内容
我们也可以使用函数来尝试上面的点。但是有一些不同之处。
this
将成员添加到函数中来指定它们。new
运算符创建其实例。下面是我尝试了上面使用对象和this
进行的所有操作,但首先创建了函数而不是直接编写对象。
/*********************************************************************
1. When you add variable to the function using this keyword, it
gets added to the function prototype, thus allowing all function
instances to have their own copy of the variables added.
*********************************************************************/
function functionDef()
{
this.name = "ObjDefinition";
this.getName = function(){
return this+":"+this.name;
}
}
obj1 = new functionDef();
document.write(obj1.getName() + "<br />"); //[object Object]:ObjDefinition
/*********************************************************************
2. Members explicitly added to the function protorype also behave
as above: all function instances have their own copy of the
variable added.
*********************************************************************/
functionDef.prototype.version = 1;
functionDef.prototype.getVersion = function(){
return "v"+this.version; //see how this.version refers to the
//version variable added through
//prototype
}
document.write(obj1.getVersion() + "<br />"); //v1
/*********************************************************************
3. Illustrating that the function variables added by both above
ways have their own copies across function instances
*********************************************************************/
functionDef.prototype.incrementVersion = function(){
this.version = this.version + 1;
}
var obj2 = new functionDef();
document.write(obj2.getVersion() + "<br />"); //v1
obj2.incrementVersion(); //incrementing version in obj2
//does not affect obj1 version
document.write(obj2.getVersion() + "<br />"); //v2
document.write(obj1.getVersion() + "<br />"); //v1
/*********************************************************************
4. `this` keyword refers to the immediate parent object. If you
nest the object through function prototype, then `this` inside
object refers to the nested object not the function instance
*********************************************************************/
functionDef.prototype.nestedObj = { name: 'nestedObj',
getName1 : function(){
return this+":"+this.name;
}
};
document.write(obj2.nestedObj.getName1() + "<br />"); //[object Object]:nestedObj
/*********************************************************************
5. If the method is on an object's prototype chain, `this` refers
to the object the method was called on, as if the method was on
the object.
*********************************************************************/
var ProtoObj = { fun: function () { return this.a } };
var obj3 = Object.create(ProtoObj); //creating an object setting ProtoObj
//as its prototype
obj3.a = 999; //adding instance member to obj3
document.write(obj3.fun()+"<br />");//999
//calling obj3.fun() makes
//ProtoObj.fun() to access obj3.a as
//if fun() is defined on obj3
4. 在构造函数内使用.
当函数用作构造函数(即使用new
关键字调用该函数)时,函数体内的this
指向正在构造的新对象。
var myname = "global context";
function SimpleFun()
{
this.myname = "simple function";
}
var obj1 = new SimpleFun(); //adds myname to obj1
//1. `new` causes `this` inside the SimpleFun() to point to the
// object being constructed thus adding any member
// created inside SimipleFun() using this.membername to the
// object being constructed
//2. And by default `new` makes function to return newly
// constructed object if no explicit return value is specified
document.write(obj1.myname); //simple function
5. 在原型链上定义的函数中使用
如果方法在对象的原型链上,那么该方法内部的this
关键字会指向调用该方法的对象本身,就好像该方法是在该对象上定义的一样。
var ProtoObj = {
fun: function () {
return this.a;
}
};
//Object.create() creates object with ProtoObj as its
//prototype and assigns it to obj3, thus making fun()
//to be the method on its prototype chain
var obj3 = Object.create(ProtoObj);
obj3.a = 999;
document.write(obj3.fun()); //999
//Notice that fun() is defined on obj3's prototype but
//`this.a` inside fun() retrieves obj3.a
6. 在call()、apply()和bind()函数内部
Function.prototype
上。this
的值,并传递任何要传递给原始函数的参数。fun.apply(obj1 [, argsArray])
将obj1
设置为fun()
内的this
值,并使用argsArray
的元素作为其参数来调用fun()
。fun.call(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])
- 将obj1
设置为fun()
内的this
值,并将arg1, arg2, arg3, ...
作为其参数来调用fun()
。fun.bind(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])
- 返回绑定了指向obj1
的this
值和fun
的参数到指定的arg1, arg2, arg3,...
参数的函数fun
的引用。apply
、call
和bind
之间的区别必须已经变得明显了。 apply
允许我们将函数的参数指定为类似数组的对象,即具有数字length
属性和相应非负整数属性的对象。而call
允许我们直接指定函数的参数。 apply
和call
都立即在指定的上下文中调用函数并使用指定的参数。另一方面,bind
仅仅返回绑定到指定this
值和参数的函数,我们可以通过将其分配给变量来捕获此返回的函数的引用,稍后可以随时调用它。function add(inc1, inc2)
{
return this.a + inc1 + inc2;
}
var o = { a : 4 };
document.write(add.call(o, 5, 6)+"<br />"); //15
//above add.call(o,5,6) sets `this` inside
//add() to `o` and calls add() resulting:
// this.a + inc1 + inc2 =
// `o.a` i.e. 4 + 5 + 6 = 15
document.write(add.apply(o, [5, 6]) + "<br />"); //15
// `o.a` i.e. 4 + 5 + 6 = 15
var g = add.bind(o, 5, 6); //g: `o.a` i.e. 4 + 5 + 6
document.write(g()+"<br />"); //15
var h = add.bind(o, 5); //h: `o.a` i.e. 4 + 5 + ?
document.write(h(6) + "<br />"); //15
// 4 + 5 + 6 = 15
document.write(h() + "<br />"); //NaN
//no parameter is passed to h()
//thus inc2 inside add() is `undefined`
//4 + 5 + undefined = NaN</code>
7. this
在事件处理程序中的作用
this
关键字会引用到对应的元素。这种直接函数赋值可以通过 addeventListener
方法或传统的事件注册方法(如 onclick
)实现。<button onclick="...this..." >
)中直接使用 this
,它会引用到该元素本身。this
将会解析为全局对象 window
。attachEvent
将函数附加到事件处理程序时,会出现与上述相同的行为。它不是将函数分配给事件处理程序(从而使函数成为元素的方法),而是在事件上调用函数(实质上在全局上下文中调用函数)。我建议在 JSFiddle 上尝试一下。
<script>
function clickedMe() {
alert(this + " : " + this.tagName + " : " + this.id);
}
document.getElementById("button1").addEventListener("click", clickedMe, false);
document.getElementById("button2").onclick = clickedMe;
document.getElementById("button5").attachEvent('onclick', clickedMe);
</script>
<h3>Using `this` "directly" inside event handler or event property</h3>
<button id="button1">click() "assigned" using addEventListner() </button><br />
<button id="button2">click() "assigned" using click() </button><br />
<button id="button3" onclick="alert(this+ ' : ' + this.tagName + ' : ' + this.id);">used `this` directly in click event property</button>
<h3>Using `this` "indirectly" inside event handler or event property</h3>
<button onclick="alert((function(){return this + ' : ' + this.tagName + ' : ' + this.id;})());">`this` used indirectly, inside function <br /> defined & called inside event property</button><br />
<button id="button4" onclick="clickedMe()">`this` used indirectly, inside function <br /> called inside event property</button> <br />
IE only: <button id="button5">click() "attached" using attachEvent() </button>
8. ES6箭头函数中的this
在箭头函数中,this
的行为类似于普通变量:它将从其词法作用域继承。箭头函数定义时所在的函数的this
将成为箭头函数的this
。
因此,这与以下行为相同:
(function(){}).bind(this)
请看以下代码:
const globalArrowFunction = () => {
return this;
};
console.log(globalArrowFunction()); //window
const contextObject = {
method1: () => {return this},
method2: function(){
return () => {return this};
}
};
console.log(contextObject.method1()); //window
const contextLessFunction = contextObject.method1;
console.log(contextLessFunction()); //window
console.log(contextObject.method2()()) //contextObject
const innerArrowFunction = contextObject.method2();
console.log(innerArrowFunction()); //contextObject
this
考虑以下函数:
function foo() {
console.log("bar");
console.log(this);
}
foo(); // calling the function
请注意,我们正在正常模式下运行,即未使用严格模式。
在浏览器中运行时,this
的值将作为 window
记录。这是因为在 Web 浏览器的作用域中,window
是全局变量。
如果您在像 node.js 这样的环境中运行相同的代码,则 this
将引用您的应用程序中的全局变量。
现在,如果我们通过在函数声明开头添加语句 "use strict";
来在严格模式下运行此代码,则在任何一个环境中,this
都不再引用全局变量。这样做是为了避免在严格模式下出现混淆。在这种情况下,this
仅会记录 undefined
,因为它确实是未定义的。
接下来,我们将看到如何操作 this
的值。
有不同的方法可以做到这一点。如果您已经在 JavaScript 中调用过本地方法,例如 forEach
和 slice
,那么您应该已经知道,在这种情况下,this
变量指的是您调用该函数的 Object
(请注意,在 JavaScript 中,几乎所有东西都是 Object
,包括 Array
和 Function
)。例如,看下面的代码:
var myObj = {key: "Obj"};
myObj.logThis = function () {
// I am a method
console.log(this);
}
myObj.logThis(); // myObj is logged
如果一个 Object
包含一个保存 Function
的属性,则该属性称为方法。当调用此方法时,它的 this
变量始终被设置为与其关联的 Object
。这适用于严格模式和非严格模式。this
的引用。例如:// continuing with the previous code snippet
var myVar = myObj.logThis;
myVar();
// logs either of window/global/undefined based on mode of operation
考虑一个更为常见的实际场景:
var el = document.getElementById('idOfEl');
el.addEventListener('click', function() { console.log(this) });
// the function called by addEventListener contains this as the reference to the element
// so clicking on our element would log that element itself
new
关键字考虑一个Javascript中的构造函数:
function Person (name) {
this.name = name;
this.sayHello = function () {
console.log ("Hello", this);
}
}
var awal = new Person("Awal");
awal.sayHello();
// In `awal.sayHello`, `this` contains the reference to the variable `awal`
这是如何运作的呢?嗯,让我们看看当我们使用new
关键字时会发生什么。
new
关键字调用函数将立即初始化类型为Person
的Object
。Object
的构造函数设置为Person
。另请注意,typeof awal
只会返回Object
。Object
将被分配为Person.prototype
的原型。这意味着Person
原型中的任何方法或属性都将对所有Person
实例(包括awal
)可用。Person
本身现在被调用;其中this
是指新构造的对象awal
。相当简单,不是吗?
请注意,官方ECMAScript规范没有明确说明这些类型的函数是实际的constructor
函数。它们只是普通的函数,new
可以用于任何函数。只是我们将其用作这样的函数,因此我们只称之为这样的函数。
call
和apply
因此,由于function
也是Objects
(实际上是Javascript中的一类变量),即使函数也有它们自己的方法,这些方法本身也是函数。
所有函数都继承自全局的Function
,它的许多方法之一是call
和apply
,两者都可用于操作调用它们的函数中的this
的值。
function foo () { console.log (this, arguments); }
var thisArg = {myObj: "is cool"};
foo.call(thisArg, 1, 2, 3);
这是使用 call
的典型示例。它基本上取第一个参数,并将 this
在函数 foo
中设置为对 thisArg
的引用。传递给 call
的所有其他参数都作为参数传递给函数 foo
。{myObj: "is cool"}, [1, 2, 3]
。这是一种非常好的方法来更改任何函数中的 this
值。
apply
几乎与 call
相同,只不过它只接受两个参数:thisArg
和包含要传递给函数的参数的数组。因此,上面的 call
调用可以转换为如下的 apply
:foo.apply(thisArg, [1,2,3])
注意,call
和apply
可以覆盖我们在第二个bullet中讨论的点方法调用设置的this
值。
很简单:)
bind
!bind
是call
和apply
的兄弟。它也是JavaScript中所有函数从全局Function
构造函数继承的一种方法。 bind
和call
/apply
之间的区别在于,call
和apply
实际上会调用函数。另一方面,bind
返回一个具有预设thisArg
和arguments
的新函数。让我们通过示例更好地理解这一点:function foo (a, b) {
console.log (this, arguments);
}
var thisArg = {myObj: "even more cool now"};
var bound = foo.bind(thisArg, 1, 2);
console.log (typeof bound); // logs `function`
console.log (bound);
/* logs `function () { native code }` */
bound(); // calling the function returned by `.bind`
// logs `{myObj: "even more cool now"}, [1, 2]`
看到它们之间的区别了吗?虽然微小,但它们的用法不同。与call
和apply
一样,bind
也会覆盖由点方法调用设置的this
的值。
还要注意,这三个函数都不会对原函数进行任何更改。call
和apply
将返回新构造函数的值,而bind
将返回新构造的函数本身,准备好被调用。
有时,您不喜欢this
随作用域(特别是嵌套作用域)的变化。请看以下示例。
var myObj = {
hello: function () {
return "world"
},
myMethod: function () {
// copy this, variable names are case-sensitive
var that = this;
// callbacks ftw \o/
foo.bar("args", function () {
// I want to call `hello` here
this.hello(); // error
// but `this` references to `foo` damn!
// oh wait we have a backup \o/
that.hello(); // "world"
});
}
};
在上面的代码中,我们可以看到this
的值随着嵌套作用域而发生了变化,但我们希望使用来自原始作用域的this
的值。所以我们将this
'复制' 到that
并使用副本而不是this
。聪明吧?
索引:
this
默认存储了什么内容?new
关键字会怎样?call
和 apply
来操作this
?bind
。this
以解决嵌套作用域问题。"this" 与作用域有关。每个函数都有自己的作用域,由于 JS 中的一切都是对象,甚至一个函数也可以使用 "this" 将一些值存储到自身中。OOP(面向对象编程)101 教导我们,“this” 仅适用于对象的实例。因此,每次函数执行时,该函数的新“实例”都会有新的“this”含义。
当人们尝试在匿名闭包函数内部使用 "this" 时,大多数人会感到困惑,例如:
(function(value) { this.value = value; $('.some-elements').each(function(elt){ elt.innerHTML = this.value; // 哎呀!!可能是未定义的 }); })(2);
所以,在 each() 内部,"this" 不会持有您期望的“value”(来自它上面的
this.value = value;)。为了解决这个问题,开发人员可以:
(function(value) { var self = this; // 小改动 self.value = value; $('.some-elements').each(function(elt){ elt.innerHTML = self.value; // 啊!== 2 }); })(2);
试一下吧,你会开始喜欢这种编程模式。
this
关键字与作用域无关,在非对象属性的函数中也有意义。 - Bergithis
取决于包含它的函数如何被调用——而不是该函数所在的位置。 - Scott Marcus由于这个主题被顶起来了,我为那些对this
话题不熟悉的读者编写了几个要点。
this
的值是如何确定的?我们使用this
的方式类似于自然语言(如英语)中使用代词的方式:“John is running fast because he is trying to catch the train.” 相反,我们也可以写成“…John is trying to catch the train”。
var person = {
firstName: "Penelope",
lastName: "Barrymore",
fullName: function () {
// We use "this" just as in the sentence above:
console.log(this.firstName + " " + this.lastName);
// We could have also written:
console.log(person.firstName + " " + person.lastName);
}
}
this
在定义它的函数被对象调用之前,不会被赋值。在全局范围内,所有全局变量和函数都定义在window
对象上。因此,全局函数中的this
指代(并具有)全局window
对象的值。
当使用严格模式use strict
时,在全局和未绑定到任何对象的匿名函数中,this
的值为undefined
。
当我们借用使用this
的方法、将使用this
的方法分配给变量、将使用this
的函数作为回调函数传递以及在闭包——内部函数中使用this
时,this
关键字是最容易被误解的。(2)
在ECMA Script 6中定义,箭头函数采用封闭作用域(函数或全局)的this
绑定。
function foo() {
// return an arrow function
return (a) => {
// `this` here is lexically inherited from `foo()`
console.log(this.a);
};
}
var obj1 = { a: 2 };
var obj2 = { a: 3 };
var bar = foo.call(obj1);
bar.call( obj2 ); // 2, not 3!
bind()
的方式,但重要的是要注意,它们实质上是禁用了传统的this
机制,而采用更广为人知的词法作用域。(1)
参考资料:
this
在JavaScript中始终指向正在执行的函数的“所有者”。
如果没有明确的所有者定义,则引用最顶层的所有者,即window对象。
因此,如果我执行:
function someKindOfFunction() {
this.style = 'foo';
}
element.onclick = someKindOfFunction;
this
将引用元素对象。但要小心,很多人会犯这个错误。
<element onclick="someKindOfFunction()">
在后一种情况下,你仅仅是引用函数,而不是把它交给元素。因此,this
将引用window对象。
JavaScript中的每个执行上下文都有一个this参数,由以下方式设置:
eval
调用的您可以使用func.call
、func.apply
或func.bind
来设置this的值。
默认情况下,最常让初学者感到困惑的是,当DOM元素上抛出事件后调用监听器时,函数的this值是该DOM元素。
jQuery通过jQuery.proxy使更改这一点变得非常简单。
this
不是函数本身的内在属性,而是函数被调用时的一种产物。请注意不要改变原意。 - Pointythis
不是指函数的作用域。this
将引用特定的对象(或可能是 undefined
),正如您所说,可以使用 .call()
或 .apply()
进行更改。函数的 作用域 是指它可以访问哪些变量(在简化时),这完全取决于函数声明的位置,不能更改。 - nnnnnnDaniel,讲得很好!关于这个问题,请简单介绍一下并列出与事件处理程序相关的this
执行上下文指针列表。
简而言之,在JavaScript中,this
指向运行当前函数的对象(或其执行上下文所在的对象),它始终是只读的,无法设置(尝试设置将导致“无效的左侧赋值”消息)。
对于事件处理程序:内联事件处理程序(例如<element onclick="foo">
)将覆盖任何早期和之前附加的其他处理程序,因此要小心,并最好完全避免使用内联事件委托。
感谢Zara Alaverdyan通过异议辩论激发我制作这个例子列表:)
el.onclick = foo; // 在foo中,this指向obj
el.onclick = function () {this.style.color = '#fff';} // this指向obj
el.onclick = function() {doSomething();} // 在doSomething中,this指向window
el.addEventListener('click',foo,false) // 在foo中,this指向obj
el.attachEvent('onclick, function () { // this }') // this指向window,IE中的所有兼容性 :)
<button onclick="this.style.color = '#fff';"> // this指向obj
<button onclick="foo"> // 在foo中,this指向window,但可以使用<button onclick="foo(this)">
这里是一个关于在JavaScript中使用this
的好资源。
这里是摘要:
全局的this
在浏览器中,全局作用域下的this
是window
对象。
<script type="text/javascript">
console.log(this === window); // true
var foo = "bar";
console.log(this.foo); // "bar"
console.log(window.foo); // "bar"
在使用Node的repl时,this
是顶级命名空间。你可以将其称为global
。
>this
{ ArrayBuffer: [Function: ArrayBuffer],
Int8Array: { [Function: Int8Array] BYTES_PER_ELEMENT: 1 },
Uint8Array: { [Function: Uint8Array] BYTES_PER_ELEMENT: 1 },
...
>global === this
true
在脚本中执行 node
时,全局作用域下的 this
开始时为空对象。它与 global
不同。\\test.js
console.log(this); \\ {}
console.log(this === global); \\ fasle
函数中的this
除非在DOM事件处理程序的情况下或提供了thisArg
(请参见下文),否则无论是在节点还是在使用this
的浏览器中,在未使用new
调用的函数中使用this
引用全局范围…
<script type="text/javascript">
foo = "bar";
function testThis() {
this.foo = "foo";
}
console.log(this.foo); //logs "bar"
testThis();
console.log(this.foo); //logs "foo"
</script>
如果您使用use strict;
,那么this
将变为undefined
<script type="text/javascript">
foo = "bar";
function testThis() {
"use strict";
this.foo = "foo";
}
console.log(this.foo); //logs "bar"
testThis(); //Uncaught TypeError: Cannot set property 'foo' of undefined
</script>
如果您使用new
调用函数,this
将是一个新的上下文,它不会引用全局的this
。<script type="text/javascript">
foo = "bar";
function testThis() {
this.foo = "foo";
}
console.log(this.foo); //logs "bar"
new testThis();
console.log(this.foo); //logs "bar"
console.log(new testThis().foo); //logs "foo"
</script>
您创建的函数将成为函数对象。它们会自动获得一个特殊的prototype
属性,您可以向其分配值。当使用new
调用函数创建实例时,您可以访问分配给prototype
属性的值。您可以通过this
来访问这些值。
function Thing() {
console.log(this.foo);
}
Thing.prototype.foo = "bar";
var thing = new Thing(); //logs "bar"
console.log(thing.foo); //logs "bar"
通常将数组或者对象赋值给prototype
是一个错误的做法。如果你希望每个实例拥有自己的数组,应该在函数中创建它们而不是在原型中。
function Thing() {
this.things = [];
}
var thing1 = new Thing();
var thing2 = new Thing();
thing1.things.push("foo");
console.log(thing1.things); //logs ["foo"]
console.log(thing2.things); //logs []
你可以在对象上的任何函数中使用this
,来引用该对象上的其他属性。这与使用new
创建的实例不同。
var obj = {
foo: "bar",
logFoo: function () {
console.log(this.foo);
}
};
obj.logFoo(); //logs "bar"
在HTML DOM事件处理程序中,this
始终是对附加了事件的DOM元素的引用。
function Listener() {
document.getElementById("foo").addEventListener("click",
this.handleClick);
}
Listener.prototype.handleClick = function (event) {
console.log(this); //logs "<div id="foo"></div>"
}
var listener = new Listener();
document.getElementById("foo").click();
除非您将上下文绑定
function Listener() {
document.getElementById("foo").addEventListener("click",
this.handleClick.bind(this));
}
Listener.prototype.handleClick = function (event) {
console.log(this); //logs Listener {handleClick: function}
}
var listener = new Listener();
document.getElementById("foo").click();
在 HTML 属性中可以放置 JavaScript,this
是一个指向元素的引用。
<div id="foo" onclick="console.log(this);"></div>
<script type="text/javascript">
document.getElementById("foo").click(); //logs <div id="foo"...
</script>
您可以使用eval
访问this
。
function Thing () {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
eval("console.log(this.foo)"); //logs "bar"
}
var thing = new Thing();
thing.logFoo();
您可以使用 with
将this
添加到当前作用域,以便在不显式引用 this
的情况下读取和写入 this
的值。
function Thing () {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
with (this) {
console.log(foo);
foo = "foo";
}
}
var thing = new Thing();
thing.logFoo(); // logs "bar"
console.log(thing.foo); // logs "foo"
在许多情况下,jQuery中的this
指的是DOM元素。
<div class="foo bar1"></div>
<div class="foo bar2"></div>
<script type="text/javascript">
$(".foo").each(function () {
console.log(this); //logs <div class="foo...
});
$(".foo").on("click", function () {
console.log(this); //logs <div class="foo...
});
$(".foo").each(function () {
this.click();
});
</script>
Global Context (i.e. Outside all functions):
Outside all functions (i.e. in global context) the "current object" (and hence the value of "this") is always the "window" object for browsers.
Inside Direct "Non Bound Function" Call:
Inside a Direct "Non Bound Function" Call, the object that invoked the function call becomes the "current object" (and hence the value of "this"). If a function is called without a explicit current object, the current object is either the "window" object (For Non Strict Mode) or undefined (For Strict Mode) . Any function (or variable) defined in Global Context automatically becomes a property of the "window" object.For e.g Suppose function is defined in Global Context as
function UserDefinedFunction(){
alert(this)
}
it becomes the property of the window object, as if you have defined it as
window.UserDefinedFunction=function(){
alert(this)
}
In "Non Strict Mode", Calling/Invoking this function directly through "UserDefinedFunction()" will automatically call/invoke it as "window.UserDefinedFunction()" making "window" as the "current object" (and hence the value of "this") within "UserDefinedFunction".Invoking this function in "Non Strict Mode" will result in the following
UserDefinedFunction() // displays [object Window] as it automatically gets invoked as window.UserDefinedFunction()
In "Strict Mode", Calling/Invoking the function directly through "UserDefinedFunction()" will "NOT" automatically call/invoke it as "window.UserDefinedFunction()".Hence the "current object" (and the value of "this") within "UserDefinedFunction" shall be undefined. Invoking this function in "Strict Mode" will result in the following
UserDefinedFunction() // displays undefined
However, invoking it explicitly using window object shall result in the following
window.UserDefinedFunction() // "always displays [object Window] irrespective of mode."
Let us look at another example. Please look at the following code
function UserDefinedFunction()
{
alert(this.a + "," + this.b + "," + this.c + "," + this.d)
}
var o1={
a:1,
b:2,
f:UserDefinedFunction
}
var o2={
c:3,
d:4,
f:UserDefinedFunction
}
o1.f() // Shall display 1,2,undefined,undefined
o2.f() // Shall display undefined,undefined,3,4
In the above example we see that when "UserDefinedFunction" was invoked through o1, "this" takes value of o1 and the value of its properties "a" and "b" get displayed. The value of "c" and "d" were shown as undefined as o1 does not define these properties
Similarly when "UserDefinedFunction" was invoked through o2, "this" takes value of o2 and the value of its properties "c" and "d" get displayed.The value of "a" and "b" were shown as undefined as o2 does not define these properties.
Inside Indirect "Non Bound Function" Call through functionName.call and functionName.apply:
When a "Non Bound Function" is called through functionName.call or functionName.apply, the "current object" (and hence the value of "this") is set to the value of "this" parameter (first parameter) passed to call/apply. The following code demonstrates the same.
function UserDefinedFunction()
{
alert(this.a + "," + this.b + "," + this.c + "," + this.d)
}
var o1={
a:1,
b:2,
f:UserDefinedFunction
}
var o2={
c:3,
d:4,
f:UserDefinedFunction
}
UserDefinedFunction.call(o1) // Shall display 1,2,undefined,undefined
UserDefinedFunction.apply(o1) // Shall display 1,2,undefined,undefined
UserDefinedFunction.call(o2) // Shall display undefined,undefined,3,4
UserDefinedFunction.apply(o2) // Shall display undefined,undefined,3,4
o1.f.call(o2) // Shall display undefined,undefined,3,4
o1.f.apply(o2) // Shall display undefined,undefined,3,4
o2.f.call(o1) // Shall display 1,2,undefined,undefined
o2.f.apply(o1) // Shall display 1,2,undefined,undefined
The above code clearly shows that the "this" value for any "NON Bound Function" can be altered through call/apply. Also,if the "this" parameter is not explicitly passed to call/apply, "current object" (and hence the value of "this") is set to "window" in Non strict mode and "undefined" in strict mode.
Inside "Bound Function" Call (i.e. a function that has been bound by calling functionName.bind):
A bound function is a function whose "this" value has been fixed. The following code demonstrated how "this" works in case of bound function
function UserDefinedFunction()
{
alert(this.a + "," + this.b + "," + this.c + "," + this.d)
}
var o1={
a:1,
b:2,
f:UserDefinedFunction,
bf:null
}
var o2={
c:3,
d:4,
f:UserDefinedFunction,
bf:null
}
var bound1=UserDefinedFunction.bind(o1); // permanantly fixes "this" value of function "bound1" to Object o1
bound1() // Shall display 1,2,undefined,undefined
var bound2=UserDefinedFunction.bind(o2); // permanantly fixes "this" value of function "bound2" to Object o2
bound2() // Shall display undefined,undefined,3,4
var bound3=o1.f.bind(o2); // permanantly fixes "this" value of function "bound3" to Object o2
bound3() // Shall display undefined,undefined,3,4
var bound4=o2.f.bind(o1); // permanantly fixes "this" value of function "bound4" to Object o1
bound4() // Shall display 1,2,undefined,undefined
o1.bf=UserDefinedFunction.bind(o2) // permanantly fixes "this" value of function "o1.bf" to Object o2
o1.bf() // Shall display undefined,undefined,3,4
o2.bf=UserDefinedFunction.bind(o1) // permanantly fixes "this" value of function "o2.bf" to Object o1
o2.bf() // Shall display 1,2,undefined,undefined
bound1.call(o2) // Shall still display 1,2,undefined,undefined. "call" cannot alter the value of "this" for bound function
bound1.apply(o2) // Shall still display 1,2,undefined,undefined. "apply" cannot alter the value of "this" for bound function
o2.bf.call(o2) // Shall still display 1,2,undefined,undefined. "call" cannot alter the value of "this" for bound function
o2.bf.apply(o2) // Shall still display 1,2,undefined,undefined."apply" cannot alter the value of "this" for bound function
As given in the code above, "this" value for any "Bound Function" CANNOT be altered through call/apply. Also, if the "this" parameter is not explicitly passed to bind, "current object" (and hence the value of "this" ) is set to "window" in Non strict mode and "undefined" in strict mode. One more thing. Binding an already bound function does not change the value of "this". It remains set as the value set by first bind function.
While Object Creation through "new":
Inside a constructor function, the "current object" (and hence the value of "this") references the object that is currently being created through "new" irrespective of the bind status of the function. However if the constructor is a bound function it shall get called with predefined set of arguments as set for the bound function.
Inside Inline DOM event handler:
Please look at the following HTML Snippet
<button onclick='this.style.color=white'>Hello World</button>
<div style='width:100px;height:100px;' onclick='OnDivClick(event,this)'>Hello World</div>
The "this" in above examples refer to "button" element and the "div" element respectively.
In the first example, the font color of the button shall be set to white when it is clicked.
In the second example when the "div" element is clicked it shall call the OnDivClick function with its second parameter referencing the clicked div element. However the value of "this" within OnDivClick SHALL NOT reference the clicked div element. It shall be set as the "window object" or "undefined" in Non strict and Strict Modes respectively (if OnDivClick is an unbound function) or set to a predefined Bound value (if OnDivClick is a bound function)