scope查看对象方法的问题

时间:2014-07-10 11:10:09

标签: javascript oop scope this eventhandler

我试过搜索了很多S.O.页面,但没有任何东西在这个顶部完全触及,同时也没有使用JQUERY ....我试图坚持纯JavaScript,因为我想学习它115%,然后推进我目前的JQuery知识。

我有一个名为ScreenResizeTool的对象......

function ScreenResizeTool(currImg) {
    window.addEventHandler('resize', function() {
        listen(currImg);
    }, true);
}

和这样的方法......

ScreenResizeTool.prototype.listen = function(currImg) {
    //Random Code For Resizing
};

对于经验丰富的JavaScript用户来说,我的麻烦可能是显而易见的,但是我很难将其变成一个乱糟糟的糟糕的OOP集。我已经做了各种测试来向自己展示并证明addEventHandler中的this在绑定到窗口时会发生变化。我在测试之前就已经假设了这一点,但是我能够看到,一旦window.resize事件发生,listen方法就消失了,而不是全局窗口变量的一部分....

我还尝试在对象构造函数中添加this捕获,例如this.me = this,但是一旦它运行,它也无法看到me变量。一旦窗口使用了该函数,它就不再了解me变量或对类方法的任何引用....

我知道我可以将它区分开来,但我的目标是学习如何完全封装和使用尽可能多的干净OOP结构,因为我刚从.NET世界来到我生命中需要它。 / p>

我也知道我可以制作凌乱的调用或者存储这个对象或访问窗口变量中的方法,但这对我来说似乎是完全错误的。我应该能够完全封装这个对象,并让它的事件和方法都在这个类结构中实现。

我也知道currImg变量也不会被看到,但让我们从这里开始。我假设一旦我弄清楚我对JavaScript范围的错误思路,我应该很好地找出问题。

我知道那里有1000名JavaScript程序员正在等待我提出一个新的问题而不是问这个简单的问题但我必须知道...

有人想到吗?

2 个答案:

答案 0 :(得分:1)

JavaScript中this的整个概念对于初学者来说是一场噩梦,在我的代码中,我通常会尽量避免它,因为它会让人很快混淆并使代码无法读取(恕我直言)。此外,许多刚接触JavaScript但面向对象编程语言经验丰富的人尝试直接进入整个thisprototype内容,尽管实际上并不需要(google JS模式如<强> IIFE 例如作为替代品)。

所以看看原始代码:

function ScreenResizeTool(currImg) {
    window.addEventHandler('resize', function() {
        listen(currImg); // global function listen?
    }, true);
}

ScreenResizeTool.prototype.listen = function(currImg) {
    //Random Code For Resizing
};

首先,你可能意味着addEventListener。在它的回调中,你引用listen但是作为一个全局变量,将其视为window.listen - 它不会退出。所以你可以考虑这样做:

function ScreenResizeTool(currImg) {
    window.addEventHandler('resize', function() {
        this.listen(currImg); // what's this?
    }, true);
}

如果您想使用prototype.listen的{​​{1}}功能。但这不会起作用,因为事件监听器的回调函数是使用不同的ScreenResizeTool而不是this调用的,这是您的函数范围。 这就是让大多数程序员感到畏缩的地方,你必须缓存this,代码我看到的例子:

this

让我们只使用后者来引用事件回调中的函数:

var _this = this;
var that = this;
var _self = this;

现在这实际上可以工作并执行您想要实现的目标:调用function ScreenResizeTool(currImg) { var _self = this; window.addEventListener('resize', function() { _self.listen(); }, true); } 的{​​{1}}函数。 请参阅此JSFiddle以获取一个工作示例:http://jsfiddle.net/KNw6R/(检查控制台是否输出)

总而言之,这个问题与使用jQuery没有任何关系。这是JS的一般问题。特别是当必须处理不同的浏览器实现时,您应该使用jQuery(或其他类似的库)来使您自己的代码干净整洁,而不是使用多个if语句来找出以什么方式支持哪些功能。

答案 1 :(得分:1)

绑定到DOM对象(如this)的函数内的

window将始终引用该对象。
构造函数内的this将始终引用prototype

如您所述,绕过this问题的常见做法是将其缓存在变量中,通常称为self。现在您希望实例化后对象的变量和属性可用,因此您需要的是return关键字,更具体地说是返回父对象本身。让我们把它们放在一起:

function ScreenResizeTool() {
  var self = this;
  // method to instantiate the code is often stored in init property
  this.init = function() {
    window.addEventListener('resize', function() {
       self.listen(); // self will refer to the prototype, not the window!
    }, true);
  };
  return this;
}
ScreenResizeTool.prototype.listen = function() { // Dummy function
  var h = window.innerHeight, w = window.innerWidth;
  console.log('Resized to ' + w + ' x ' + h + '!');
};

很简单吧?所以我们现在有了原型,但如果不是实例,原型就无法做任何事情。因此,我们创建了ScreenResizeTool的实例,并使用其init方法实例化它:

var tool = new ScreenResizeTool();
tool.init();
// every time you resize the window now, a result will be logged!

您也可以简单地存储listen&amp; init方法作为构造函数中的私有函数,并在匿名对象中返回它们:

function ScreenResizeTool() {
  var listen = function() { ... };
  var init = function() { ... };
  // in this.init you can now simply call listen() instead of this.listen()
  return {
    listen: listen,
    init: init
  }
}

查看fiddle并确保打开控制台。请注意,在这种情况下,我宁愿使用第一个函数而不是第二个函数(它完全相同)因为原型仅在您有多个实例或子类时才有用