我正在尝试找到一种从对象方法本身引用对象的当前实例的简单方法(类似于任何体面语言中的this
关键字)。
我尝试了很多“为自己存储指针”的变体(如window.window.window
do),但总会出错。例如:
function ClassA() {
var mySelf = this;
this.myMethod = function() {
console.log(mySelf); //Once you extend this class, mySelf will not be available
}
}
function ClassB() {
this.mySelf = this; //Ok, now you can extend this and mySelf will be there
this.myMethod = function() {
console.log(mySelf);//"mySelf is not defined" because it's a property now
console.log(this.mySelf);//Value of 'this' and 'self' will vary
console.log(RandomContainer.ClassBInstance.mySelf);//I can't use a defined path
}
}
由于JavaScript中的所有OOP都是hackish,我不得不问......
是否有任何魔法可以引用当前对象调用方法?
评论中有很多可能的解决方案,谢谢大家! 但我仍然需要改进我的问题。因此,我会在失败的尝试中添加一些代码,然后尝试提出的解决方案......
function BaseController()
{
var myPriv = 42;
return {
getAnswer: function() {
return myPriv;
}
};
}
function SomeController()
{
return {
showAnswer: function()
{
var answer;
answer = myPriv; //I need some way to access this
answer = getAnswer(); //Also a way to refer to my own methods
//(I don't even find a way to call 'showAnswer' from this context)
console.log('The answer is ' + answer);
}
};
}
//That's how I was extending my classes so far...
var someControllerInstance = jQuery.extend(
new BaseController(),
new SomeController()
);
someControllerInstance.getAnswer(); //Works!
someControllerInstance.showAnswer(); //Reference errors...
答案 0 :(得分:5)
如果你让我迟钝,你就会以错误的心态接近JavaScript。它不是为经典继承而设计的,也不是为受保护的属性或方法设计的,并且以这种方式弯曲它没有任何好处。说实话,我发现高耸的遗产堆栈是一种阅读和导航的痛苦,除非你有一个可以花费一周时间加载的全能舞蹈IDE。你可以实现更接近平坦和开放 - 同时保持灵活性 - 你编码的效果越好,可能接管你工作的其他编码人员也会感谢你。 (显然是意见)
有关原型继承的更多信息,请阅读以下信息性文章:
http://davidwalsh.name/javascript-objects-deconstruction
以下是原型继承的示例,应该注意Object.create
和isPrototypeOf
相对较新,并且对于较旧的JavaScript解释器不存在。然而,大多数情况下可以使用近似的填充物。
简单地说,当您从对象借用方法的角度考虑它们时,JavaScript变得更加强大,而不是从稍微不那么具体的实例中严格继承的实例;或者更糟糕的是,一次又一次地重建相同功能的构造函数。
以下只是一个例子,在我编写ECMAScript的16年中,我几乎不需要任何接近经典继承的东西,也不需要在原型链上大量继承的对象。通常情况下,我的js基本上只是一些新创建的对象,正确的名称间隔,从固定的函数池中借用方法;任何类型的检测都是鸭子型的,我小心翼翼地保持一切尽可能本地化。
无论如何,这是我经常使用的东西:
var Make = function(construct){
return Object.create(construct);
};
var Extend = function(proto, props){
var instance = Object.create(proto);
for ( var i in props ) { instance[i] = props[i]; }
instance.super = proto; // this should never be needed really
return instance;
};
var Animal = {
keepBreathing: function(){
console.log('animal', this);
}
};
var Monkey = Extend(Animal, {
climbTree: function(){
console.log('monkey', this);
console.log('monkey', this.super);
}
});
var KeyserSoze = Make(Monkey);
KeyserSoze.keepBreathing(); /// animal, instance of KeyserSoze
KeyserSoze.climbTree(); /// monkey, instance of KeyserSoze
console.log('an instance of monkey', KeyserSoze);
console.log('has animal as proto', Animal.isPrototypeOf(KeyserSoze)); // true
console.log('has monkey as proto', Monkey.isPrototypeOf(KeyserSoze)); // true
虽然上面的确遵循一种经典的布局,即Monkey继承了Animal的方法,但你可以用不同的方式处理事物。以下内容对动态更改更加开放,事实上您可以完全切换出另一个界面的行为对象。同样,这只是一个例子,您不必以固定的方式构建事物。
我更有可能使用的东西:
var AnimalBehaviours = {
keepBreathing: function(){
(this.breathCount === undefined) && (this.breathCount = 0);
this.breathCount++;
}
};
var ApeLikeDescendant = (function( behaviours ){
return {
create: function( config ){
return Object.create(this).prep(config);
},
prep: function( config ){
/// do your instance specific set up here
return this;
},
climbTree: function(){
console.log('ape-like', this);
},
keepBreathing: function(){
return behaviours.keepBreathing.apply(this, arguments);
},
switchBehaviours: function(newBehaviours){
behaviours = newBehaviours;
}
};
})(AnimalBehaviours);
var DouglasAdams = ApeLikeDescendant.create({});
你可以调整上面的行为,以类似于mixin的方式行事,即你采取行为,逐步完成并将它们合并到ApeLike对象......无论你的目标是什么,它都非常开放。
我经常使用的东西:
var ElementEdgeCases = {
makeWorkOnNetscape47: function(){
this.target; /// Intentionally left almost blank.
}
};
var ElementFinagler = (function(){
var finagle = {
target: null,
prep: function( element ){
this.target = element;
return this;
},
addClass: function(){
var c = this.target.getAttribute('className'); /// and so on ...
return this;
},
elaborate: function( mixin ){
for ( var i in mixin ) {
if ( mixin.hasOwnProperty(i) ) {
this[i] = mixin[i];
}
}
return this;
}
};
return function( element ){
return Object.create(finagle).prep(element);
};
})();
var elm = document.getElementsByTagName('body')[0];
ElementFinagler(elm)
.elaborate(ElementEdgeCases) // extend the object if we need
.addClass('hello world')
;
使用JavaScript时要记住的主要事情是没有任何函数属于任何东西,不是真的。每次执行函数时,函数的上下文都会被调用该函数的方式所暗示 - 上下文是在调用时计算的。这样可以提供很大的灵活性,同时您提到每次调用function.apply(context, args)
或function.call(context, arg, arg, ...)
都很麻烦;很容易编纂你自己的系统来隐藏那些重复。
哦,在我忘记之前,从上面的代码中拿走的另一件事是没有重复的函数创建。每个实例在内存中共享相同的功能。如果您计划创建大规模应用程序,请记住这一点很重要,因为您可以使用多个函数实例快速占用内存。
所以回顾一下:
apply
或call
更改上下文时,在需要其他对象时借用方法。答案 1 :(得分:0)
this
引用来自dom节点的事件源自,或javascript对象是它的子节点。按此顺序。
this.parentNode
引用dom节点的父节点(不确定它是否在对象上下文中工作)。
当我编写javascript时,我通常会尝试利用html的dom本身,将注意事项放在一边,注意JS需要如何引用它们。