1

I am learning JavaScript and I am trying to replicate some of the built-in methods like .push() .indexOf() etc..

So far so good and it is helping me a lot to learn the core of JavaScript.

But I came across .bind() and I can´t figure out a way of knowing the function that is calling the .bind() and tell my new .bind2() method to use it with the new THIS from our Object.

This is what I am trying:

const human = {
  firstName:"Humano",
  lastName: "Doe",
  fullName: function() {
    return this.firstName + "  " + this.lastName;
  }
};

const member = {
  firstName:"Member",
  lastName: "Nilsen",
};

Function.prototype.bind2 = function(obj) {
        if (typeof obj !== "object" ) {throw `${obj} is not an Object, I will work hard to return undefined later on`};
        return function(){
                return obj;
        }
    };

let testBind2 = human.fullName.bind2(member);
console.log(testBind2()); // {firstName: 'Member', lastName: 'Nilsen'}

So all I could do is to return the THIS from the Object passed as an argument but I have no idea how I can grab inside the .bind2() the fullName method (or any method that we want to bind) from the object that is actually calling the method .bind2().

Once we could grab the fullName we can pass it to bind2() and tell it to use THIS from our object.

This is only for the sake of learning and it would be amazing if someone could tell me if it is possible and how.

Thank you

1
  • 1
    hint: var that=this; and return that.apply(this, arguments) Commented May 6, 2022 at 2:00

1 Answer 1

1

don't modify window

bind is part of Function.prototype, so you can try implementing it there. Here is a possible polyfill -

Function.prototype.bind2 = function bind2(context, ...a) {
  return (...b) => this.call(context, ...a, ...b)
}

const human = {
  firstName:"Humano",
  lastName: "Doe",
  fullName: function() {
    return this.firstName + "  " + this.lastName;
  }
};

const func = human.fullName.bind2(human)

console.log(func())

Humano Doe

binding arguments

bind can receive arguments when calling bind and also when the bound function is called. Below we demonstrated that myfunc.bind2 has the exact same behavior as myfunc.bind -

Function.prototype.bind2 = function bind2(context, ...a) {
  return (...b) => this.call(context, ...a, ...b)
}

function myfunc(a,b,c) {
  console.log("name", this.name)
  console.log("sum", a + b + c)
}

const human = { name: "julio" }

const hello1 = myfunc.bind(human, 10)
const hello2 = myfunc.bind2(human, 10)

hello1(20, 30)
hello2(20, 30)

name julio
sum 60
name julio
sum 60

not just for objects

Do not make the assumption that bind only works with objects. You can bind any variable to the context -

Function.prototype.bind2 = function bind2(context, ...a) {
  return (...b) => this.call(context, ...a, ...b)
}

function myfunc(times) {
  return this.toUpperCase().repeat(times)
}

const foo = myfunc.bind2("hello")

console.log(foo(10))

HELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLO

without call

In your comment you asked how to write bind without using Function.prototype.call. If you want to include context in your binding, the only other option is to use Function.prototype.apply -

Function.prototype.bind2 = function bind2(context, ...a) {
  return (...b) => this.apply(context, a.concat(b))
}

function myfunc(times) {
  return this.toUpperCase().repeat(times)
}

const foo = myfunc.bind2("hello")

console.log(foo(10))

without context

.call and .apply give you the ability to set the this context for the bound function. You can instead add a context parameter. Choose any name for it that suits you -

Function.prototype.bind2 = function bind2(...a) {
  return (...b) => this(...a, ...b)
}

function myfunc(context, times) {
  return context.toUpperCase().repeat(times)
}

const foo = myfunc.bind2("hello")

console.log(foo(10))

any other way?

Is .call and .apply the only way to set the context? For all intents and purposes, yes. However, you can write a very bad hack if you just want to see how something like this could be possible. One caveat of this approach is that it only works for object contexts, not simple primitives like number or string -

// ⚠️ demo only, never do this
Function.prototype.bind2 = function bind2(context, ...a) {
  if (typeof context != "object") {
    throw Error("context must be an object")
  }
  return (...b) => {
    const bound = Symbol()
    context[bound] = this
    const value = context[bound](...a, ...b)
    delete context[bound]
    return value
  }
}

function myfunc(a,b,c) {
  console.log("name", this.name)
  console.log("sum", a + b + c)
}

const hello = myfunc.bind2({ name: "julio" }, 10)

hello(20, 30)

name julio
sum 60
Sign up to request clarification or add additional context in comments.

11 Comments

@Julio I added two more sections to address this comment. Please let me know if that helps :D
that is correct. in order to set this you must use call or apply. you can do it without but it is extremely hacky and you should never do it. see the last section in my answer for a demo.
Amazing Mulan !! Thank you very much I just wanted to know how bind really works by trying to create a method that does the same thing. It is a good way to really dig into the core of JavaScript. Thank you very much again
You're very welcome. Just for your reference, the reason the last one works is because if I call someObj.someFunc(args), the context of someFunc will automatically be set to someObj. So in order to replicate that, we assign the function, this, to context[bound], and then call the function context[bound](...args) which sets context as the context for the function :D
Yes, that is exactly correct. When an object with a function property is called, the object is set as the this context. In your previous example, context = this; context(...a, ...b) is no different than this(...a, ...b) which is an ordinary function call that does not set this. In your bind3 be careful with key = "key" as context may already have a key property present. Symbol() was used in my example because it is guaranteed to be unique and I made sure to delete the key after the function was run :D
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.