2

I did a sort function that passing an array as a parameter return a new array with the index positions sorted by the name of the item.

P.E: if the input is ["dog", "cat", "tiger"] the expected output will be [1, 0, 2]

Without Prototype method

let sortIndexes = (a) => {
    var aClone = a.slice(0);
    return a.sort().map(x => aClone.indexOf(x));
}

let animals = ["dog", "cat", "tiger"];
var result = sortIndexes(animals); 
console.log(result) // [1, 0, 2] 

Well, this code works, but I think is better do the same adding an Array Prototype method. And I try it...

With Prototype

Array.prototype.sortIndexes = () => {
    var aClone = this.slice(0); //Console Error in this line
    return this.sort().map(x => aClone.indexOf(x));
}

let animals = ["dog", "cat", "tiger"];
var result = animals.sortIndexes(); 

I expected the same result that without using prototype, but this error console occurs:

Cannot read property 'slice' of undefined

How can do this using Array Prototype?

Thanks!

Community
  • 1
  • 1
Aral Roca
  • 5,442
  • 8
  • 47
  • 78
  • Please read [Arrow function vs function declaration / expressions: Are they equivalent / exchangeable?](http://stackoverflow.com/q/34361379/218196) – Felix Kling Mar 25 '16 at 18:53

2 Answers2

4

That is the beauty of Arrow functions,

Array.prototype.sortIndexes = function(){
    var aClone = this.slice(0); //Console Error in this line
    return this.sort().map(x => aClone.indexOf(x));
}

let animals = ["dog", "cat", "tiger"];
var result = animals.sortIndexes(); 

console.log(result); // [1, 0, 2] 

Arrow function will bind the lexical scope into it automatically. Here in your case the lexical scope is window. So window.slice is undefined. Hence it is throwing error.

And the main rule is that you cannot force the scope of an arrow function with another one by using bind/call/etc.. So we have to be very careful while deciding when to use arrow functions.

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
Rajaprabhu Aravindasamy
  • 66,513
  • 17
  • 101
  • 130
  • `Cannot read property 'slice' of undefined` means that the context `this` is `undefined` (but not `window` as you mention). Probably `strict mode` is enabled. – Dmitri Pavlutin Mar 25 '16 at 18:51
  • 1
    And it's not the problem in `lexical scope`. It's the `context` of the function invocation: `this`. – Dmitri Pavlutin Mar 25 '16 at 18:53
  • Scope and `this` are different things. – Felix Kling Mar 25 '16 at 18:54
  • @DmitriPavlutin Arrow function decides the `this` based on which scope it is getting executed. – Rajaprabhu Aravindasamy Mar 25 '16 at 18:55
  • Arrow functions don't decide anything. They simply resolve `this` lexically. This also means that the scope is determined when / where the function is *defined*, **not** where/when it is *executed*. – Felix Kling Mar 25 '16 at 18:57
  • @FelixKling Thanks for correcting the words usage of mine. (Non native english speaker here) I was trying to tell about execution of this `var x = () => { "something"; }` code, not `x()`. – Rajaprabhu Aravindasamy Mar 25 '16 at 19:01
  • @RajaprabhuAravindasamy Probably a formulation like this is easier to follow: "Arrow functions keep the context `this` of the function from the lexical scope where it was defined. That's why you lost the array instance, because `this` is `undefined` in `.sortIndexes()`'s outer scope (`strict mode` is enabled)". – Dmitri Pavlutin Mar 25 '16 at 19:05
  • @DmitriPavlutin That's fine. But I am still wondering on which case, the `this` of an arrow function would becomes undefined. https://jsfiddle.net/2vvf9x98/1/ I tested it here with strict mode. Still cannot repro what OP said. May be OP mentioned the error message in wrong manner? – Rajaprabhu Aravindasamy Mar 25 '16 at 19:10
  • @RajaprabhuAravindasamy Your fiddle still has `window` as this. Just wrap it into an IIFE with strict mode enabled: https://jsfiddle.net/kmnpt9em/ – Dmitri Pavlutin Mar 25 '16 at 19:13
  • @DmitriPavlutin Your explanations and this answer http://stackoverflow.com/a/9822631/1209018 has cleared my doubts. Thanks again :) – Rajaprabhu Aravindasamy Mar 25 '16 at 19:21
1

Arrow functions don't bind this to the element being iterated, instead this simply remains bound to the enclosing scope: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions

Scott Marcus
  • 64,069
  • 6
  • 49
  • 71
  • 1
    Nit: The don't *bind* `this` at all, they simply resolve `this` lexically, like any other variable. – Felix Kling Mar 25 '16 at 18:55
  • @FelixKling `this` isn't a variable - it is a keyword that is bound to an object reference and that binding cannot be changed (unless a containing function is called with `call`, `apply`, `bind`, `forEach`, `map`, etc.). Arrow functions use the `lexical binding` of this. The binding process for `this` takes place when a function's Activation Object is created. – Scott Marcus Mar 25 '16 at 19:01
  • Sure. All I am saying is that arrow functions are not *binding* `this` in the sense how `.bind` binds `this`. *"The binding process for this takes place when a function's Activation Object is created."* Activation objects don't exist anymore in ES6. `this` is not bound in arrow functions: http://www.ecma-international.org/ecma-262/6.0/index.html#sec-function-environment-records: *"A function Environment Record is a declarative Environment Record that is used to represent the top-level scope of a function and, if the function is not an ArrowFunction, provides a `this` binding. "* – Felix Kling Mar 25 '16 at 19:04
  • @FelixKling True, but then again, I didn't say they did bind as in `.bind()`, but they do actually bind. – Scott Marcus Mar 25 '16 at 19:06
  • 1
    Well, I hope my quote from the spec convinces you otherwise. I agree that `this` is not resolved *exactly* like other variables, but it is not bound. The relevant part of the spec is http://www.ecma-international.org/ecma-262/6.0/index.html#sec-resolvethisbinding and http://www.ecma-international.org/ecma-262/6.0/index.html#sec-getthisenvironment . – Felix Kling Mar 25 '16 at 19:07
  • I'll have to read up on the Activation Object deprecation, but from what I see, my statement still holds, `this` is a keyword and it does get bound (except in specific instances that the language specifies that it should not be bound). Arrow functions don't cause `this` to be bound, that's true, but `this` is still bound, it's just bound to the lexical scope. – Scott Marcus Mar 25 '16 at 19:15
  • In case there was a misunderstanding here, I'm only talking about arrow functions. Of course the environment of regular functions has a `this` binding. – Felix Kling Mar 25 '16 at 19:17
  • Yes, I think we are having a circular discussion. You initially said that `this` resolves like any other variable and my main point here is that `this` isn't a variable and doesn't resolve like one. You can't, for example, set a value into this directly. It is a special keyword and it does get bound (except when the language says it shouldn't), rather than assigned. – Scott Marcus Mar 25 '16 at 19:20