最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

JavaScript nested object reference to parent - Stack Overflow

programmeradmin3浏览0评论

I'm working on a fairly plex object in JS and I'm running into issues:

I have the following (abridged) code:

var LocationSelector;

LocationSelector = function(container) {
  this.selectors = {
    container: container,
    city_name: container.find('input.city_name'),
    city_id: container.find('input.city_id')
  };
  return this.initialize();
};

LocationSelector.prototype = {
  initialize: function() {
    return this.city.checkStatus();
  },
  city: {
    status: null,
    message: null,
    id: null,
    checkStatus: function() {
      if (LocationSelector.selectors.city_name.val() && LocationSelector.selectors.city_id.val()) {
        return LocationSelector.city.setStatus('success');
      }
    },
    setStatus: function(status) {
      return alert(status);
    }
  }
};

Two questions:

1) Inside of a sub-object function this no longer refers back to the root object. It seems I can refer back to the parent if I write out LocationSelector.object.method( args ), but that's a lot to type. Is there a way to define a shortcut back to the parent object?

2) In some situations I need to have several instances of this per page, so it's important to me that I can set the various selectors when a new object is instantiated and then refer to the instance selectors in the prototype. Is referring to the parent object (ie. LocationSelector) in sub-object methods even viable for that? How does JS know to stay with the currently active object's stored properties?

Basically, I'm trying to implement a class, and I'm totally new to JS and don't really know how to do it. So, any help or suggestions are appreciated. Thanks!

I'm working on a fairly plex object in JS and I'm running into issues:

I have the following (abridged) code:

var LocationSelector;

LocationSelector = function(container) {
  this.selectors = {
    container: container,
    city_name: container.find('input.city_name'),
    city_id: container.find('input.city_id')
  };
  return this.initialize();
};

LocationSelector.prototype = {
  initialize: function() {
    return this.city.checkStatus();
  },
  city: {
    status: null,
    message: null,
    id: null,
    checkStatus: function() {
      if (LocationSelector.selectors.city_name.val() && LocationSelector.selectors.city_id.val()) {
        return LocationSelector.city.setStatus('success');
      }
    },
    setStatus: function(status) {
      return alert(status);
    }
  }
};

Two questions:

1) Inside of a sub-object function this no longer refers back to the root object. It seems I can refer back to the parent if I write out LocationSelector.object.method( args ), but that's a lot to type. Is there a way to define a shortcut back to the parent object?

2) In some situations I need to have several instances of this per page, so it's important to me that I can set the various selectors when a new object is instantiated and then refer to the instance selectors in the prototype. Is referring to the parent object (ie. LocationSelector) in sub-object methods even viable for that? How does JS know to stay with the currently active object's stored properties?

Basically, I'm trying to implement a class, and I'm totally new to JS and don't really know how to do it. So, any help or suggestions are appreciated. Thanks!

Share Improve this question asked Apr 23, 2012 at 3:28 AndrewAndrew 43.2k53 gold badges183 silver badges285 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 6

There are many things wrong with your current approach. Here is something closer to what you want, although I do not understand why LocationSelector instances have a city member.

function LocationSelector(container) {
  this.selectors = {
    container: container,
    city_name: container.find("input.city_name"),
    city_id: container.find("input.city_id")
  };

  this.city = new City(this);
  this.city.checkStatus();
}

function City(locationSelector) {
  this.status = null;
  this.message = null;
  this.id = null;
  this.locationSelector = locationSelector;
}

City.prototype.checkStatus = function () {
  if (this.locationSelector.selectors.city_name.val() && this.locationSelector.selectors.city_id.val()) {
    this.setStatus("success");
  }
};

City.prototype.setStatus = function () {
  alert("status");
};

Things to note:

  1. Data properties go on the instance, not the prototype. Only methods go on the prototype.
  2. City is clearly its own class, so you should make it one. In your code, a single city is being shared between all instances of LocationSelector, since it is put on the prototype. In this code, it is assigned as an instance property, in the LocationSelector constructor.
  3. You cannot reference LocationSelector.selectors like you do in your example. LocationSelector.selectors would be for "static" properties, which LocationSelector does not have. Instead you need to refer to the selectors property on specific instances; in this example, that instance is given by this.locationSelector.
  4. Points 2 and 3 speak to an important fact: the "child" City instance cannot reference to properties of the "parent" LocationSelector class without having a concrete instance of it.

Here is a version of the code that makes more sense to me, removing the part where LocationSelector has a city property (which it doesn't use).

function LocationSelectors(container) {
  this.city_name = container.find("input.city_name");
  this.city_id = container.find("input.city_id");
}

function City(locationSelectors) {
  this.locationSelector = locationSelector;
}

City.prototype.checkStatus = function () {
  if (this.locationSelectors.city_name.val() && this.locationSelectors.city_id.val()) {
    this.setStatus("success");
  }
};

City.prototype.setStatus = function () {
  alert("status");
};

function checkCityStatus(container) {
  var locationSelectors = new LocationSelectors(container);
  var city = new City(locationSelectors);

  city.checkStatus();
}

I leave you with a link to Crockford's "Private Members in JavaScript", which talks about doing OO in JavaScript. There are other, probably better explanations out there, but at least that one will put you on the right track.

Read about Closures and I'm positive you will find what you need.

Here's is a quick example of what you are trying to acplish:

function MyCoolObject(name){
   var self_myCoolObject = this;
   this.name = name;
   this.popAlertWithNameInFiveSeconds = function(){
       setTimeout(function(){
         alert('Incorrect reference to name "this.name" returns ' + this.name);
         alert('Correct reference to name "self_myCoolObject.name" returns ' + self_myCoolObject.name);
       },5000)
   }
}

//TO TEST
var MyObj = new MyCoolObject('MySuperCoolName')
MyObj.popAlertWithNameInFiveSeconds();

Here is a snippet of JS code that I have. Before I drop down into a click handler, I make a reference to the object (SlideShow) by calling var parent = this. Then in later nested functions, you can be sure you're calling the right scope by using parent.function()

/* Slide Show object */
function SlideShow(parentContainerId) {

    this.BEGINNING  = 'Beginning';
    this.END        = 'End of list';
    this.FIRSTINDEX = 0;

    this.length     = jQuery(parentContainerId + ' img').length;
    this.container  = jQuery(parentContainerId);
    this.imgs       = jQuery(parentContainerId + ' img');
    this.index      = this.FIRSTINDEX;
    this.status     = 'beginning';           // beginning, end



    this.init = function() {
        // get it started
        this.moveTo(this.FIRSTINDEX);
        this.process();

        // ****GET OBJECT SCOPE*****
        var parent      = this;

        // set up click listener
        this.container.find('img').click(function(e) {
            var item_width = jQuery(this).width();
            var x_click_ps = e.clientX - jQuery(this).offset().left;
            var x_diff     = x_click_ps / item_width;




            console.log(this);
            if (x_diff < .5) {
                parent.moveByIncrement(-1)
                parent.process();
            } else {
                parent.moveByIncrement(1);
                parent.process();
            }

        });
    }


.
.
.
}
发布评论

评论列表(0)

  1. 暂无评论