Anthony Chung
Anthony Chung

Reputation: 1477

Coding JS Underscore _.extend from scratch

Extend has proven challenging because I'm trying to manipulate the arguments object.

My current extend function does not account for more than one argument after the initial given object

  _.extend = function(object, sources) {
    return _.reduce(sources, function(memo, current) {
      memo[Object.keys(sources)] = current || 0;
      return memo;
    }, object)
  }

At first, I tried to make a copy of the arguments object, turn it into an array, and shift() the first argument out. This is terribly inelegant, but has still proven to be ineffective

I realized that apply() or call() should be used in this context somehow. When I tried it, it also didn't work.

_.extend = function(object) {
  var copy = [].slice.call(arguments);
  copy.shift();
  doIT.apply(this, copy);
  var doIt = function(copy) {
    return _.reduce(copy, function(memo, current) {
      memo[Object.keys(copy)] = current || 0;
      return memo;
    }, object)
  }
  doIt(copy);
}

Any ideas on what I can do to fix this?

Upvotes: 0

Views: 500

Answers (1)

MinusFour
MinusFour

Reputation: 14423

There's no need to use apply on your function, just call it normally. By doing so, you are passing your shifted array as a list of arguments into your function. Since you are only working with copy in your parameter list then only one argument would make it. There's no need for call either, as you can easily invoke the function since no this context is required. Lastly, since your function is not a function declaration, it won't be available until the expression holding the function has been evaluated (available after var doIt).

Now, your doIt function is doing something wrong:

memo[Object.keys(copy)] = current || 0;

Object.keys(copy) returns an array with copy keys. So you are doing:

memo[array] = current || 0;

The array will be casted to a string, but it's definitely not something you want either. What you need to is iterate each element properties of the copy array (each on is on current) and copy those properties into your first object (memo accumulator). Like this:

var extend = function (object) {
    var copy = [].slice.call(arguments);
    copy.shift();
    var doIt = function (copy) {
        return copy.reduce(function (memo, current) {
            Object.keys(current).forEach(function (key) {
                memo[key] = current[key];
            });
            return memo;
        }, object)
    }
    return doIt(copy);
}

However, extends still need to handle the appropriated getters and setters. So you'll need to do something like:

var extend = function (object) {
    var copy = [].slice.call(arguments);
    copy.shift();
    var doIt = function (copy) {
        return copy.reduce(function (memo, current) {
            Object.keys(current).forEach(function (key) {
                var pDesc = Object.getOwnPropertyDescriptor(current, key);
                Object.defineProperty(memo, key, pDesc);
            });
            return memo;
        }, object)
    }
    return doIt(copy);
}

Upvotes: 1

Related Questions