0

Is there a way for a function to get the object value before the function name? Below is an example of what I am kinda trying to achieve. I want to be able to read the myElement variable within the function but not pass it as a parameter but pass it before the function with the dot.

Any simple examples or explanations would be most helpful.

var myElement = document.getElementById('myID');

myElement.myFunction();

function myFunction() {
     alert(myElement);
}
melpomene
  • 84,125
  • 8
  • 85
  • 148
Peter
  • 145
  • 2
  • 2
  • 9
  • 1
    `myElement.myFunction` is undefined (and unrelated to `myFunction`), so you don't have a function to call in the first place. – melpomene Jun 15 '18 at 17:29
  • @melpomene Yes, you are right. What I am trying to do is make a function that works just like the link below but instead of it being getAttribute() it can be my own function. https://pastebin.com/ZYvxYXyQ – Peter Jun 15 '18 at 17:36
  • *"but not pass it as a parameter"* Why not? That would be most sensible thing to do. – Felix Kling Jun 15 '18 at 17:54

2 Answers2

1

The only way you could do this is to add myFunction to HTMLElements prototype (which is what gets returned by document.getElementById(). That's usually frowned upon, but if it's your own project and you know what you do, you could do that.

var myElement = document.getElementById('myID');

HTMLElement.prototype.myFunction = function() {
  console.log(this);
}

myElement.myFunction();
<div id="myID"></div>

With this prototype in place, you can call myFunction on every HTMLElement in your code.


In regards to your last comment, the function could be

HTMLElement.prototype.myFunction = function() {
  alert(this.id);
}

I don't see why you should do it, as it's much easier to just do

alert(myElement.id);

In regards to the comments, here's what I'd do. Instead of extending anything, create your own class (or function), that takes a HTMLElement. Now on this class, you can add whatever method you want, manipulate your element and then return the plain HTMLElement from a getter. You can obviously change that to whatever return you want.

class MyHtmlElement {
  constructor(htmlElement) {
    this._htmlElement = htmlElement;
  }

  alertId() {
    alert(this._htmlElement.id);
    // optional
    return this;
  }

  logId() {
    console.log(this._htmlElement.id);
    // optional
    return this;
  }
  
  setId(newId) {
    this.htmlElement.id = newId;
    // optional
    return this;
  }

  setStyle(prop, val) {
    this._htmlElement.style[prop] = val;
    // optional
    return this;
  }

  get htmlElement() {
    return this._htmlElement;
  }

  set htmlElement(value) {
    this._htmlElement = value;
  }
}

const el = new MyHtmlElement(document.getElementById('foo'));

el
  .setId('bar')
  .logId()
  .alertId()
  .setStyle('background-color', 'red')
  .setStyle('width', '100vw')
  .setStyle('height', '100vh');
  
// If you need the plain element, return it

const plainHTMLElement = el.htmlElement;
console.log(plainHTMLElement);
<div id="foo"></div>
baao
  • 71,625
  • 17
  • 143
  • 203
  • Why is it frowned upon? – Peter Jun 15 '18 at 17:39
  • 1
    I added a link in the questions text, please check that before you do it. https://stackoverflow.com/questions/14034180/why-is-extending-native-objects-a-bad-practice ... As I said, if it's your own project and the code won't be used in a plugin or library, it shouldn't be too much of a problem – baao Jun 15 '18 at 17:40
  • 2
    @Peter It's just bad design to modify an existing class, it breaks encapsulation. Adding new methods to the HTMLElement prototype is confusing for others, and for Future You who will come back to this code next year and scratch their head. There's also the possibility of a browser update adding a method with the same name, conflicting with your custom method. – Domino Jun 15 '18 at 18:05
  • @JacqueGoupil So there is less of a chance of a conflict with example A `myOwnFunction(element)` over example B `element.myOwnFunction()`? What are the odds that my function overwrites another function that has the same name? – Peter Jun 16 '18 at 22:23
  • @Peter The risk are slims and there are ways to avoid that, but honestly I think at this point I'm just to get you confused with JavaScript quirks. I'd recommend learning the basic principles of OOP before anything else. – Domino Jun 17 '18 at 04:39
  • I second Jacque @Peter. Next is just a friendly recommendation on what I would or wouldn’t do... As long as you need to ask those questions, don’t extend native JavaScript objects. If you know what you’re doing then it can be fine, otherwise you’re just running into bugs later on. The benefit of chaining your function to the object isn’t worth that. – baao Jun 17 '18 at 05:51
  • @Peter I've added something to the answer, maybe have a look at that – baao Jun 17 '18 at 06:37
  • @JacqueGoupil The reason I ask is that I want to write some code that I can use often that does not conflict with my projects if other libraries or new versions of javascript and NodeJS are used. I had a feeling that if I did use the `element.` before the function it could cause some issues in the future compared to if I just passed it as an parameter. Now for proper terminology wouldn't `element.myFunction()` actually be a method not a function? – Peter Jun 18 '18 at 02:47
0

When a function is stored in an object and then called with theObject.theFunction(), the value of this within the function will be theObject.

function sayHello() {
  alert('Hello, my name is ' + this.name);
}

let myObject = { name: 'Bob', speak: sayHello };
myObject.speak(); // shows the message 'Hello, my name is Bob'

Now if you want to be able to create your own function and let it be used by an Element, you either need to store the function in the Element instance first or to add it to the Element prototype, both of which I highly discourage. If you feel like you have to do this, there's a flaw in your design.

Still, if you have a good reason to add a custom method to an existing object, I recommend you look up lessons about prototype inheritance in JavaScript, or read my old answer about it here if you're not sure how it works. You could say, make a function which adds methods to an object when it is called, like this:

function addMethods(elem) {
  elem.speak = sayHello;
}

let myElement = document.getElementById('myID');
addMethods(myElement);

myElement.speak(); // Hello, my name is <value of the element's name attribute>

Or you could add the method to the prototype of all elements:

Element.prototype.speak = sayHello;
let myElement = document.getElementById('myID');
myElement.speak();

While browsers have let people do this since forever ago, there is technically no guarantee that Element is publicly available, or that its prototype is modifiable, or that you can add methods to Element instances. The Prototype framework (an inconveniently named third party library) has been using these techniques for a long time, but it did cause them a couple issues. jQuery prefers using a different approach, wrapping elements in another object on which custom methods are put.

Domino
  • 6,314
  • 1
  • 32
  • 58