这是JavaScript中最神秘的功能之一,在将对象方法分配给其他变量后,绑定(此关键字)丢失
var john = {
name: 'John',
greet: function(person) {
alert("Hi " + person + ", my name is " + this.name);
}
};
john.greet("Mark"); // Hi Mark, my name is John
var fx = john.greet;
fx("Mark"); // Hi Mark, my name is
我的问题是:
1)作业背后发生了什么? var fx = john.greet; 是按价值复制还是按参考复制? fx和john.greet指向两个不同的功能,对吧?
2)由于fx是一个全局方法,因此范围链仅包含全局对象。 Variable对象中 此 属性的值是多少?
答案 0 :(得分:13)
john.greet("Mark")
实际上调用了一个函数。当您执行var fx = john.greet;
时,您将获得对该功能的引用。因此,当您调用它时,this
不会绑定到john
。您实际执行的操作是window.fx("Mark")
,因此this
是window
对象。当你说它处于全球范围内时,你走在了正确的轨道上。在此特定实例中,全局对象为window
,因此fx
实际为window.fx
。
如果要设置功能参考,则应使用call
或apply
,如果要设置this
的值。试着这样做:
fx.call(john, "Mark");
call
或apply
中的第一个参数是函数调用上下文中this
使用的值。
修改强>
有些人提到这里的真正问题可能是围绕对象文字与对象实例的混淆。您正在创建一个对象文字,其行为也类似于单身。您无法创建该对象的新实例。在这种情况下,john
是对该对象文字的引用。在该上下文中,函数this
中的greet
指的是对象文字本身。因此,当您致电john.greet("Mark")
时,this
绑定到john
。
当您单独获取对john.greet
的引用并将其分配给全局变量时,您基本上就是这样做:
var fx = function(person) {
alert("Hi " + person + ", my name is " + this.name);
}
在这种情况下,this
为window
,因为fx
基本上是window.fx
(因为此处的全局对象是window
。假设此代码已被包装在另一个函数中,全局对象将引用该函数。
如果要创建对象的多个实例,可以执行以下操作:
var Person = function(name) {
var self = this; //maintains a reference to the instance
this.name = name;
this.greet = function(name) {
alert("Hi " + name + ", my name is " + self.name);
}
}
var john = new Person("John");
john.greet("Mark"); // alerts "Hi Mark, my name is John"
var fx = john.greet;
fx("Mark"); // also alerts "Hi Mark, my name is John"
这里,self
变量(函数的本地变量)维护对实际实例的引用,因为在创建对象时它将它绑定到this
。
在Javascript中有许多与OOP相关的最佳实践。你可以谷歌找出(有很多链接)。我建议特别是从道格拉斯·克罗克福德那里读书。
答案 1 :(得分:6)
1)fx
和john.greet
指的是同一个函数对象,对象的赋值操作,按引用工作。
对于原始值,例如String
,Number
,Boolean
undefined
或null
,将会复制该值。
2)this
值指的是全局对象。
this
值不是Variable Object的属性,它与范围链无关,是一个特殊的保留字,并且是隐式确定的当function is called时(您也可以通过call
或apply
明确设置)。
JavaScript内部处理Reference type
,它由两个组件组成,基础对象和属性名称,当调用函数时,GetValue
1}}值是通过获取基础对象(通过内部new
操作)隐式确定的。
最后,隐式设置this
的最后一种情况是,当您使用{{3}}运算符调用函数时,this
关键字将引用新创建的对象。
简而言之,以下是this
隐式 的工作方式:
1-当函数作为方法调用时(该函数作为对象的成员被调用):
this
2- 正常函数调用:
obj.method(); // 'this' inside method will refer to obj
3-使用myFunction(); // 'this' inside the function will refer to the Global object
// or
(function () {})();
运算符时:
new
答案 2 :(得分:3)
据我了解,您只是将该方法分配给变量“fx”。 john对象的上下文并没有随之而来。
在我的脑海中,在fx的上下文中“this”将引用全局对象,在浏览器的上下文中(我相信)等同于您的窗口对象。
(编辑以澄清全局对象。排序)
答案 3 :(得分:1)
因为你只是将fx设置为greet方法而不是整个john对象,所以它没有它的父级概念,并且变为全局范围。所以从本质上说,它只是通过复制方法传递价值。
由于该函数现在是全局范围的,因此“this”成为Window对象。
如果你改为将fx设置为john,你会得到预期的结果。
var john = {
name: 'John',
greet: function(person) {
alert("Hi " + person + ", my name is " + this.name);
}
};
john.greet("Mark"); // Hi Mark, my name is John
var fx = john;
fx.greet("Mark"); // Hi Mark, my name is John
答案 4 :(得分:0)
所以我的建议是尽可能避免在我们第一次使用时这个
var self = this;
我们应该在所有函数(原型函数,无论如何)中使用self而不是this,但如果我们写这样的东西:
function MyObject = {
var self = this;
};
MyObject.prototype = {
method1 = function(data){
self.data = data;
}
}
这不起作用,因为原型是MyObject中的一个对象,它无法访问MyObject拥有的私有成员 self 。我的解决方案很简单:
function MyObject = {
var self = this;
MyObject.prototype.method1 = function(data){
self.data = data;
};
}
这有利于原型的效率,而且我们也不必关心所有这个问题。虽然我们会输入很多 MyObject.prototype.xxxx 的东西。
如果这对你们有帮助,请给我一些大拇指,这样我就可以在大拇指中获得15点声望,谢谢。