我希望找到一个“this”关键字的明确解释,以及如何正确使用它。
它的行为似乎很奇怪,我不完全明白为什么。
这是如何工作的,何时使用?
我希望找到一个“this”关键字的明确解释,以及如何正确使用它。
它的行为似乎很奇怪,我不完全明白为什么。
这是如何工作的,何时使用?
当前回答
与其他语言相比,this关键字在JavaScript中的行为有所不同。在面向对象语言中,this关键字指的是类的当前实例。在JavaScript中,这个值由函数的调用上下文(context.function())及其调用位置决定。
1.在全局上下文中使用时
当您在全局上下文中使用它时,它将绑定到全局对象(浏览器中的窗口)
document.write(this); //[object Window]
当您在全局上下文中定义的函数中使用此函数时,它仍然绑定到全局对象,因为该函数实际上是全局上下文的方法。
function f1()
{
return this;
}
document.write(f1()); //[object Window]
f1以上是全局对象的方法。因此,我们也可以在window对象上调用它,如下所示:
function f()
{
return this;
}
document.write(window.f()); //[object Window]
2.在对象方法内部使用时
当您在对象方法中使用此关键字时,它将绑定到“立即”封闭对象。
var obj = {
name: "obj",
f: function () {
return this + ":" + this.name;
}
};
document.write(obj.f()); //[object Object]:obj
上面我把单词immediate用双引号括起来。这是为了指出,如果您将对象嵌套在另一个对象中,那么这将绑定到直接父对象。
var obj = {
name: "obj1",
nestedobj: {
name:"nestedobj",
f: function () {
return this + ":" + this.name;
}
}
}
document.write(obj.nestedobj.f()); //[object Object]:nestedobj
即使您将函数作为方法显式添加到对象中,它仍然遵循上述规则,即这仍然指向直接父对象。
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.调用无上下文函数时
当您使用这个在没有任何上下文的情况下调用的内部函数(即,不在任何对象上)时,它将绑定到全局对象(浏览器中的窗口)(即使函数是在对象内部定义的)。
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
使用函数尝试所有功能
我们也可以用函数来尝试以上几点。然而,存在一些差异。
上面我们使用对象文字表示法向对象添加了成员。我们可以通过使用这个向函数添加成员。以指定它们。对象文字表示法创建了一个我们可以立即使用的对象实例。对于函数,我们可能需要首先使用新运算符创建其实例。同样,在对象文字方法中,我们可以使用点运算符将成员显式添加到已定义的对象中。这将仅添加到特定实例。然而,我已经向函数原型添加了变量,以便它在函数的所有实例中得到反映。
下面,我尝试了我们使用Object和上面所做的所有事情,但首先创建了函数,而不是直接编写对象。
/*********************************************************************
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关键字调用时),此内部函数体指向正在构造的新对象。
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.在原型链上定义的函数内部使用时
如果该方法位于对象的原型链上,则此类方法中的这个引用该方法所调用的对象,就像该方法是在对象上定义的一样。
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()内部的值,并调用fun(()传递argsArray元素作为其参数。fun.call(obj1[,arg1[,arg2[,arg3[,…]]])-将obj1设置为fun()内部的值,并调用fun(,传递arg1,arg2,arg3,…)。。。作为其论点。fun.bind(obj1[,arg1[,arg2[,arg3[,…]]])-返回对函数fun的引用,此函数内部fun绑定到obj1,fun的参数绑定到指定的参数arg1,arg2,arg3,。。。。到目前为止,apply、call和bind之间的区别肯定已经很明显了。apply允许将参数指定为类似数组的对象,即具有数字长度属性和相应的非负整数财产的对象。而调用允许直接指定函数的参数。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.此内部事件处理程序
当您将函数直接分配给元素的事件处理程序时,直接在事件处理函数内部使用该函数将引用相应的元素。这种直接函数分配可以使用addeventListener方法或通过传统的事件注册方法(如onclick)完成。类似地,当您在元素的事件属性(如<button onclick=“…this…”>)中直接使用它时,它引用的是元素。但是,通过在事件处理函数或事件属性内调用的其他函数间接地使用该函数将解析为全局对象窗口。当我们使用Microsoft的event Registration模型方法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。
因此,这与以下行为相同:
(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
其他回答
关于这一点,最详细和最全面的文章可能是以下内容:
JavaScript中“this”关键字的温和解释
这背后的想法是理解函数调用类型对设置该值具有重要意义。
当难以识别时,不要问自己:
这是从哪里来的?
但一定要问问自己:
如何调用函数?
对于箭头函数(上下文透明的特殊情况),问问自己:
在定义箭头函数的地方有什么值?
在处理这个问题时,这种心态是正确的,会让你免于头痛。
这是JavaScript中一个被误解的概念,因为它在不同地方的行为几乎不同。简单地说,这是指我们当前正在执行的函数的“所有者”。
这有助于获取我们使用的当前对象(也称为执行上下文)。如果您了解当前函数在哪个对象中执行,那么您可以很容易地了解这是什么当前函数
var val = "window.val"
var obj = {
val: "obj.val",
innerMethod: function () {
var val = "obj.val.inner",
func = function () {
var self = this;
return self.val;
};
return func;
},
outerMethod: function(){
return this.val;
}
};
//This actually gets executed inside window object
console.log(obj.innerMethod()()); //returns window.val
//Breakdown in to 2 lines explains this in detail
var _inn = obj.innerMethod();
console.log(_inn()); //returns window.val
console.log(obj.outerMethod()); //returns obj.val
上面我们创建了3个同名“val”的变量。一个在全局上下文中,一个在obj内部,另一个在obj的innerMethod内部。JavaScript通过从本地到全局的作用域链来解析特定上下文中的标识符。
很少有地方可以区分这一点
调用对象的方法
var status = 1;
var helper = {
status : 2,
getStatus: function () {
return this.status;
}
};
var theStatus1 = helper.getStatus(); //line1
console.log(theStatus1); //2
var theStatus2 = helper.getStatus;
console.log(theStatus2()); //1
当执行第1行时,JavaScript为函数调用建立一个执行上下文(EC),将其设置为最后一个“.”之前引用的对象。因此在最后一行中,您可以理解a()是在全局上下文(即窗口)中执行的。
使用构造函数
这可用于引用正在创建的对象
function Person(name){
this.personName = name;
this.sayHello = function(){
return "Hello " + this.personName;
}
}
var person1 = new Person('Scott');
console.log(person1.sayHello()); //Hello Scott
var person2 = new Person('Hugh');
var sayHelloP2 = person2.sayHello;
console.log(sayHelloP2()); //Hello undefined
当执行new Person()时,将创建一个全新的对象。调用Person,并将其this设置为引用该新对象。
函数调用
function testFunc() {
this.name = "Name";
this.myCustomAttribute = "Custom Attribute";
return this;
}
var whatIsThis = testFunc();
console.log(whatIsThis); //window
var whatIsThis2 = new testFunc();
console.log(whatIsThis2); //testFunc() / object
console.log(window.myCustomAttribute); //Custom Attribute
如果我们错过了新的关键字,whatIsThis指的是它能找到的最全局的上下文(window)
使用事件处理程序
如果事件处理程序是内联的,则它引用全局对象
<script type="application/javascript">
function click_handler() {
alert(this); // alerts the window object
}
</script>
<button id='thebutton' onclick='click_handler()'>Click me!</button>
通过JavaScript添加事件处理程序时,这是指生成事件的DOM元素。
您还可以使用.apply().call()和.bind()操作上下文JQuery代理是另一种方法,您可以使用它来确保函数中的值符合您的要求。(检查了解$.proxy()、jQuery.proxy)用法)var that=this在JavaScript中意味着什么
javascript中的每个执行上下文都有一个this参数,该参数由以下参数设置:
如何调用函数(包括作为对象方法、调用和应用的使用、new的使用)绑定的使用箭头函数的词汇(它们采用外部执行上下文的this)代码是严格模式还是非严格模式是否使用eval调用代码
可以使用func.all、func.apply或func.bind设置此值。
默认情况下,当在DOM元素上引发事件后调用监听器时,函数的这个值就是DOM元素,这让大多数初学者感到困惑。
jQuery使用jQuery.proxy进行更改变得很简单。
作用域的用法如下
<script type="text/javascript" language="javascript">
$('#tbleName tbody tr').each(function{
var txt='';
txt += $(this).find("td").eq(0).text();
\\same as above but synatx different
var txt1='';
txt1+=$('#tbleName tbody tr').eq(0).text();
alert(txt1)
});
</script>
txt1和txt的值相同在上面的示例中$(this)=$('#tbleName tbody-tr')相同
这是我见过的最好的解释:清晰地理解JavaScripts
此引用总是指(并保持)object-一个单独的对象,通常用于函数或方法,尽管它可以在全局范围请注意,当我们使用strict模式时在全局函数和匿名函数中未定义绑定到任何对象。
有四种情况可能会令人困惑:
当我们传递一个方法(使用此方法)作为参数用作回调函数时。当我们使用内部函数(闭包)时。需要注意的是,闭包不能通过使用this关键字访问外部函数的this变量,因为this变量只能由函数本身访问,而不能由内部函数访问。当依赖于此的方法被分配给跨上下文的变量时,在这种情况下,它引用了另一个对象,而不是最初预期的对象。与bind、apply和call方法一起使用时。
他给出了代码示例、解释和解决方案,我认为这很有帮助。