2

I have the following code written for NodeJS:

/* server.js */
'use strict';

const http = require('http'),
    url = require('url');
    METHODS = ['GET','POST','PUT','DELETE'],
    _routePathIndex = Array.apply(null, Array(METHODS.length)).map(() => {return []}),
    _routeMethodIndex = _routePathIndex.slice(),
    _server = http.createServer();

_server.on('request', (req, res) => {
    let parsed = url.parse(req.url),
        methodIndexVal = METHODS.indexOf(req.method),
        PathIndexVal = _routePathIndex[methodIndexVal].indexOf(parsed.pathname);

    _routeMethodIndex[methodIndexVal][PathIndexVal](req, res);
});

module.exports = _init();

function _init(){
    let rs = { listen: _listen };
    METHODS.forEach( (val,i) => {
        rs[val.toLowerCase()] = function(route, handler){
            _routePathIndex[i].push(route);
            _routeMethodIndex[i].push(handler);
        };
    });

    return rs;
};

function _listen(port, callback){
    _server.listen(port, callback);
}

To test this out I have the I have a very simple script:

/* server.test.js */
var app = require('./server.js');
app.get('/', (req,res) => { console.log(req, res); });
app.listen(3000, () => { console.log('listening at port', 3000) });

The strangeness begins on line 2 of server.test.js which executes the following code block in server.js, I added the comments to display the values of both _routePathIndex and _routeMethodIndex.

...
        rs[val.toLowerCase()] = function(route, handler){
            /* _routePathIndex:    [ [], [], [], [], ]
               _routeMethodIndex:  [ [], [], [], [], ] */
            _routePathIndex[i].push(route);

            /* _routePathIndex:    [ ['/'], [], [], [], ]
               _routeMethodIndex:  [ ['/'], [], [], [], ] */
            _routeMethodIndex[i].push(handler);


            /* _routePathIndex:    [ ['/', [Function]], [], [], [], ]
               _routeMethodIndex:  [ ['/', [Function]], [], [], [], ] */
        }; 
...

My question is, why is the array acting as tho there are referenced to each other?

At first, I thought maybe it was the .slice() that was making the reference but I debunked that by running the following script in the same environment:

var a = [], b = a.slice();
a.push(1);
console.log(a,b); // [1] [0]

Another thing is when I don't do the .slice() trick and refactored the code to as such

...
    _routePathIndex = Array.apply(null, Array(METHODS.length)).map(() => {return []}),
    _routeMethodIndex = Array.apply(null, Array(METHODS.length)).map(() => {return []}),

the strange referencing behaviour is gone and the code works Perfect!

For added info I'm working with node -v : v5.4.1.

Also I tried to clone the array using [].concat(_routePathIndex) but it still had that weird behaviour

1
  • Array.apply(null, Array(METHODS.length)).map(() => {return []}) seems (to me) a convoluted and unreadable way of writing Array(METHODS.length).fill([]) Commented Feb 20, 2016 at 17:46

1 Answer 1

5

slice only does a shallow copy, that is _routePathIndex and _routeMethodIndex are different, but their elements are the same. Consider this simplified example:

a = [[],[]];
b = a.slice();
    
b[0].push(1);
document.write(a)

Get a picture:

enter image description here

Sign up to request clarification or add additional context in comments.

2 Comments

can't accept answer too soon, SO rules, anyway what did you use to for the cool pic?
@jkris: merribithouse.net/arrows - developed this for my own use a while ago.

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.