简体   繁体   中英

Can I provide a prototype definition of me/that/self = this in javascript?

I prefer the me/that/self method to resolve the binding 'problem' in Javascript. Anytime I declare a 'class' that will have functions that may be passed as parameters (eg event handlers). Here's an example of my general setup:

function Person(name)
{
    var me = this;

    this.name = name;

    this.alertName = function()
    {
        alert(me.name);
    };
}

var aPerson = new Person('Paul');
setTimeout(aPerson.alertName, 1000);

This works because I've defined var me = this; in the 'class' definition. This gets repetitive, so as an exercise, I wanted to abstract this and add the me = this definition to the prototype of Function so I don't have to do it manually every time. I hope the way I describe it makes sense. I thought something like this would work:

Function.prototype.me = function()
{
    return this;
}

I expected a call to me() anywhere in the Person 'class' would work, but it doesn't. I've tried different ways, for instance by extending Function with a BaseFunction class that has the definition, but I can't figure it out and I can't find anything by way of Google or on SO.

Here is a jsFiddle with what I've been playing around with if you're interested:

http://jsfiddle.net/qgjw47nt/

Thanks,

Paul

The way you're trying to use me (if I understand your question correctly), it would be considered a function assigned to an inner variable, and not a member of the function/“object” itself.

To access the me prototype, you would have to use this.me – which of course would make the whole thing moot.

var foo = function()
{
    this.doSomething = function() {
        alert('yay!'); 
    };

    // this doesn't work! "me" would refer to a non-existent variable
    me.doSomething();

    // this would work, but it's obviously useless.
    this.me.doSomething();
}

Even worse, if you'd call this.me inside a function defined inside another function, you would access the this.me of the inner function, and could never access the outer one with this approach.

The way how you are trying to define me is saying about you need to get closer understanding about this . Prototype of the Function - is the in prototype chain of all the objects you have created by new . It is have absolutely no idea about your specific object.

The handler gets invoked with context depending on the place it was invoked, not the place you have defined it. So, there is no link from handler itself to object to which it belongs.

The way how you can define and bind specific this to a function to be able to pass it all around, apart from having this stored in closure, as you doing now, is the .bind() function. You can do something like:

var foo = function (name) {
   this.name = name;
   this.handler = function () {
     console.log('I am called, name=', this.name);
   }.bind(this);
 }

 var boo = new foo('Paul');
 setTimeout(boo.handler, 1000)

Actually this is the most 'true' way how it is done in JS. Of course there a lot of sugar libs to wrap around that in different forms, but all have that bind under the hood.

But, if you are worrying about having repetitive var me = this , any other option will be also too repetitve for you :) Check the CoffeeScript - it is dream of minimalistic coding, and nightmare from some other sides.

You are probably aware that event handler functions (or a regular method in your example) you define within your constructor will always have access to the arguments your constructor was called with through the closure? Try this.

function Person(name){
    this.alertName = function(){ 
        alert(name);
    };
}

the downside of this pattern is that you can't put alertName on the prototype of Person, because it needs to access the private arguments through the closure. If you don't make use of the closure there is absolutely no need to create a new alert name function on every instance of Person.

edit: correction. getters and setters are equally bad as they keep the closure in memory just like a method, didn't think it through. so unless you actually make good use of it you should avoid using it at all, and just use the prototype when in doubt.

you need getters and setters to publish variables that are passed by value. variables passed by reference can just be published via this.yourPropertyName = yourArgumentName , as they will just both reference the same object.

 
 
 
  
  Object.defineProperty(this,"name",{ get:function(){return name}, set:function(newName){name = newName} });
 
  

You shouldn't per se bind this and not use "this" ever. Especially when it comes to methods whenever possible you should put them on the prototype, and make them generic. The term "ducktype" is often used for that. Because if you use "this" in your method, anything that has a "name" property can use Person.prototype.callName and it will just work (even if it's a duck).

If you find JavaScript too wordy, there's CoffeeScript for that:

class Person
    constructor: (@name) ->
    alertName: => alert "Hi, my name is #{@name}"

aPerson = new Person 'chka chka Slim Shady'
setTimeout aPerson.alertName, 1000

This uses the fat arrow ( => ) which ensures @ (== this ) binds to the right context.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM