Javascript 为什么将变量(对象范围之外)设置为对象方法会返回未定义的结果?
下面的代码是从中复制和粘贴的。我研究了使用JavaScript进行OOP的一般问题。但是,我是一名初学者,对此代码段有以下问题:Javascript 为什么将变量(对象范围之外)设置为对象方法会返回未定义的结果?,javascript,oop,Javascript,Oop,下面的代码是从中复制和粘贴的。我研究了使用JavaScript进行OOP的一般问题。但是,我是一名初学者,对此代码段有以下问题: 行Person.prototype.gender=''的目的是什么?如果我取出它并运行代码,我会得到相同的结果 为什么调用genderTeller()会导致“未定义”警报?从初学者的角度来看,MDN的解释似乎有点单薄。这是一个范围问题吗 我仔细阅读了这篇文章,发现对于一个还不熟悉javascript的人来说,这确实是一件多么令人困惑的事情 关于#1,我认为这是对JIT
Person.prototype.gender=''的目的是什么代码>?如果我取出它并运行代码,我会得到相同的结果
genderTeller()
会导致“未定义”警报?从初学者的角度来看,MDN的解释似乎有点单薄。这是一个范围问题吗我仔细阅读了这篇文章,发现对于一个还不熟悉javascript的人来说,这确实是一件多么令人困惑的事情 关于#1,我认为这是对JIT编译器的一个提示,“性别”是一个字符串。Javascript JIT编译器喜欢对象属性保持相同类型(在本例中为字符串)的情况。这篇文章没有描述这一点,或者这一行根本就在那里,这是愚蠢的。也许这是为了证明您可以在“新人”实例中重写原型属性 关于#2,当您在中调用object.method()时,会自动调用方法,其中堆栈将“object”填充为“this”。但是,如果您执行类似var detachedmethod=curobject.method的操作,然后调用detachedmethod(),它不会以“this”绑定为curobject进行调用(相反,在方法体中,this==未定义。或者可能是“window”,我不确定:-) 总而言之,这是一堆吹毛求疵的东西,对于javascript的日常使用来说并不重要,而且可以在您进行过程中进行学习 行
Person.prototype.gender=''的目的是什么代码>?如果我取出它并运行代码,我会得到相同的结果
这似乎为gender
属性建立了一个默认值。使用它,即使在不调用构造函数的情况下创建实例,也会设置属性:
var person2 = Object.create(Person.prototype);
console.log(person2.gender); // ""
这在创建子类型时可能很有用:
function Employee() {}
Employee.prototype = Object.create(Person.prototype);
console.log(new Employee().gender); // ""
为什么调用genderTeller()
会导致“未定义”警报
MDN应该进一步解释它,特别是“函数上下文”部分。但是,this
的值是在调用函数时确定的,而不是在何时何地定义它
通过将person1.sayGender
分配给genderTeller
,它与person1
分离。因此,它不再是特定对象的“方法”
相反,它作为一个常规函数调用,其值this
默认为全局对象,在浏览器中为window
window.gender = 'n/a';
var genderTeller = person1.sayGender;
genderTeller(); // logs: 'n/a'
对于问题1,行
Person.prototype.gender = '';
为性别属性提供一个默认值,这样即使在创建新的Person
对象时没有为其分配其他值,它也有一个未定义的默认值。”
和未定义的
之间存在差异,有时重要,有时不重要,但存在差异
对于问题2,当您这样做时:
var person1 = new Person('Male');
var genderTeller = person1.sayGender;
genderTeller(); // alerts undefined
var genderTeller = person1.sayGender;
您的变量genderTeller
包含一个函数指针,并且只包含一个函数指针。它与您的person1
对象没有关联。当您仅将其作为函数调用时,函数中的this
指针将设置为全局对象(浏览器中的窗口
)或未定义的
(如果在严格模式下运行),因此因为this
不是Person
对象,this.gender
将不包含适当的值,并且可能是未定义的
在这个错误中有一个非常重要的教训。在javascript中,这个
指针是根据调用方法的方式设置的。当您调用genderTeller()
时,您只是在调用一个函数,因此与任何特定的人
对象都没有任何关联。this
指针不会指向Person
对象,因此对this.xxx
的任何引用(假设它是Person
对象)都不会起作用
当您调用person1.sayGender()
时,这是一种非常不同的调用同一函数的方法。因为您是通过对象引用调用它的,所以javascript会将this
指针设置为person1
对象,它就会工作
这两种场景之间的差异很微妙,但在javascript中非常重要,因此我将尝试进一步解释
创建person1
对象后,该对象包含名为sayGender
的属性。该属性包含一个值,该值指向sayGender操作的函数sayGender
只是一个包含在属性中的函数(技术上是在person1
对象的原型链中,但您可以将其视为该对象上的属性)
执行此操作时:
var person1 = new Person('Male');
var genderTeller = person1.sayGender;
genderTeller(); // alerts undefined
var genderTeller = person1.sayGender;
您正在创建一个名为genderTeller
的新变量,该变量现在也包含指向同一函数的指针。但是,就像它在sayGender
属性中一样,它只是一个函数。它与任何对象都没有固有的绑定。只有通过对象引用调用它时,它才会获得与对象的绑定(或者如果您使用.call()
或.apply()
强制对象引用,但这超出了您在此处所做的操作)。当您仅调用
genderTeller()
您只是调用一个函数,它将没有与之关联的对象引用,因此当函数运行时,此
不会指向个人
对象
如上所述,可以强制对象引用。例如,您可以执行以下所有操作:
var genderTeller = person1.sayGender;
genderTeller.call(person1);
// .apply() only differs from .call() in how
// arguments are passed to the function
// since you have no arguments to sayGender() it looks the same as .call()
var genderTeller = person1.sayGender;
genderTeller.apply(person1);
var genderTeller = person1.sayGender.bind(person1);
genderTeller();
而且,它会再次起作用,因为您强制与person1
ob关联
genderTeller(); // returns undefined
gender = 'hi there';
genderTeller(); // returns 'hi there'