[英]What is the rationale behind the behavior of constructor pointer in JavaScript?
[英]What is the rationale for the behavior of the 'this' keyword in JavaScript?
我从语言设计的角度来问这个问题。 所以我试图找出答案
this
? this
是错误的,或者在可以改进? 为了澄清为什么我不安this
,看看这个例子:
var a = {};
a.f = function(){ return this; }
var f = a.f;
// f() != a.f()
请注意f()
所属的对象丢失的容易程度:与a
分开, this
将成为全局对象(浏览器的window
)。
现在考虑:
var newA = function(){
var self = {};
self.f = function(){ return self; }
return self;
}
var a = newA();
var f = a.f;
// f() == a.f() !
完全不使用this
,我们能够建立和维护对象上下文,无论方法在何处或如何使用。 我不禁想到,凭借封闭所提供的力量, this
变得多余,甚至可能有点危险......
我不是反对this
,或者想要开始争论; 我只是想更好地理解它。 我确实理解“这个”可能很有用,但也认识到它也可能令人困惑 ......当然,对于初学者而言,也许对专家来说也会让人感到困惑 。
然而,它仍然是语言的大量使用的,看似备受推崇的一部分,而当时语言的其他核心方面似乎公平的游戏,回避(即,克罗克福德并with
或new
)。 我错过了什么,这使得this
不可或缺?
您似乎期望它的行为与某些OO语言中的行为一样,它始终引用方法所属的对象。
但是在JavaScript中, 函数可以附加到多个对象,或者根本不附加任何对象。 在您的示例中,您编写了一个旨在用于特定对象的上下文中的函数 ...但是没有什么能阻止我将该函数与其他任何对象相关联。 这只是语言的本质 - 函数是一流的,对象成员资格是可选的。
因此, 这指的是调用函数的上下文。 现在,这是一个任意对象(通过.
, .
.apply
或.apply
.call()
)或全局对象。 在语言的未来版本,它会参考在其中所定义的功能的上下文:全局对象为全局函数,外this
对内部函数; 你可以将其视为设计缺陷的修正,因为实际上能够使用它来引用全局对象并不是特别有用。
我不认为让“这个”不受约束是一个错误。 起初它有时会让人感到困惑,但它有很好的理由。 首先想到的是,由于JavaScript不是基于类的语言,因此函数不与任何特定类相关联,因此没有一种将“this”自动绑定到正确对象实例的一致方法。 例如,
function Person(first, last, age) {
this.firstName = first;
this.lastName = last;
this.age = age;
}
Person.prototype.getFullName = function() {
return this.firstName + " " + this.lastName;
};
“this”需要引用Person对象,但是分配给Person.prototype.getName的函数没有任何方法可以知道它将如何被使用,所以“this”需要被绑定到它所调用的任何对象上。
如果这会导致问题,那就是当你有嵌套函数时。
// This is a really contrived example, but I can't think of anything better
Person.prototype.getInfo = function() {
// get name as "Last, First"
function getNameLastFirst() {
// oops. "this" is the global object, *not* the Person
return this.lastName + ", " + this.firstName;
}
// expect something like "Crumley, Matthew: Age 25",
// but you get "undefined, undefined: Age 25"
return getNameLastFirst() + ": Age " + this.age;
};
提出的语法artificialidiot很方便,但使用apply将“this”绑定到特定对象非常容易:
function bind(func, obj) {
return function() {
return func.apply(obj, arguments);
};
}
Person.prototype.getInfo = function() {
// get name as "Last, First"
var getNameLastFirst = bind(function () {
return this.lastName + ", " + this.firstName;
}, this);
return getNameLastFirst() + ": Age " + this.age;
};
或者使用闭包的更“传统”的方法:
Person.prototype.getInfo = function() {
var self = this;
// get name as "Last, First"
function getNameLastFirst() {
return self.lastName + ", " + self.firstName;
}
return getNameLastFirst() + ": Age " + this.age;
};
我认为未绑定的“这个”是一个错误。 否则它非常方便。 未绑定的“this”打开了错误解释在浏览器事件处理中最突出的上下文的可能性。 此外,javascript库对事件处理和许多回调结构(如map,filter)中“this”应该引用的内容有不同的看法。
删除未绑定的“此”可能不会让事情变得更加困难。
编辑:我想一个替代语法示例将使我的立场更清晰。
function Foo()
{
//both this refer to the Foo instance
this.blah=this.function(){this.bar;};
//second this refers to baz
this.blah=baz.function(){this.bar;};
//second this refers to anonymous function itself
this.blah=function(){this.bar;};
}
对不起,我真的很喜欢Python ;-)
我认为未绑定的'this'关键字是必要的,因为JavaScript是基于原型的语言。 更好的消息可以在这里填写详细信息。
尽管如此,事实上是非常无益的。 特别是如果你想将一个对象的方法传递给一个更高阶的函数,事情开始变得丑陋(以下示例在MooTools的帮助下):
myArray.each(myObject.foo);
无法工作,因为myObject.foo中的'this'将引用myArray而不是myObject。 代替:
myArray.each(myObject.foo.bind(myObject))
这对我来说似乎很难看。 这就是为什么我通常不在JavaScript中以面向对象的方式编程,但我严重依赖于闭包。
考虑成语af()
作为简写:
a.f.call(a);
根据定义,使用范围a
调用函数f
。
var f = a.f;
f(); // f.call(this);
a.f(); // f.call(a);
如果this
和a
不是同一个对象, f()
和af()
将使用不同的范围,因此可能表现不同。 考虑其他语言中静态和类方法的区别:
class Foo {
public:
static void a(Foo *scope) {
// do something with given scope
};
void b() {
a(this); // do something with the scope of this object
};
};
Foo foo;
Foo bar;
foo.a(&bar) != foo.b(); // just like f() != a.f()
foo.a(&foo) == foo.b(); // just like f.call(a) == a.f()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.