4 ms·
JavaScript. Kill the "new" operator. Make prototypes less magical (i.e. use something like `Object.create` to construct). Secondarily, kill getters and sette
by strager 15y ago
JavaScript.
Kill the "new" operator. Make prototypes less magical (i.e. use something like `Object.create` to construct).
Secondarily, kill getters and setters. (That includes `Array#length`.) I want code and data, not code, data, and code which pretends it's data.
I don't mind the JavaScript syntax much (`function () {` isn't that difficult to type or scan through after you've dealt with it for a while). I'm fine with the small core object and function set. I'm fine with the DOM (except the getters/setters part). I'm okay with `Object.prototype.hasOwnProperty.call`; that can be swept away into a function. Just don't make me write code which looks like statically-typed classical OO spaghetti. I want dynamic prototypal functional spaghetti. =]
- squidsoup 15y agoWhat do you dislike so much about constructors? I find a nice pattern using require.js (AMD) is to return a constructor function in a module, allowing the calling code to consume the module with: var module = new Module();
- tomp 15y agoThe problem with constructors is that they are completely redundant and introduce unnecessary complexity. In javascript, it hardly ever makes sense to call a constructor (e.g. a Function, Array, etc.) without the 'new' keyword, likewise it makes almost zero sense to call a normal function with the 'new' keyword. So, instead of the requiring the programmers to know which function is a normal function and which is a constructor, we could simply call all the functions normally (without 'new'), and have the function return a new object (if necessary). Kinda like what python does.
- orangecat 15y agoRight. The "new" keyword is never necessary and is usually actively counterproductive. In Java, "new Hammer()" must allocate a new object and it must be exactly a Hammer instance, and to work around those limitations we get the joy of AbstractHammerFactoryFactory. In Python, "Hammer()" can return an existing object and it can be a subclass of Hammer; callers don't need to know the details.
- strager 15y agoYes; just give me something; I don't care what it really is, as long as it works with how I use it (i.e. adheres to some interface).
- tomp 15y agoIn Java, it's a bit different. There, classes (`new Hammer()`) and function (`Hammer()`) are orthogonal concepts that cannot be mixed, while in JavaScript, they are one and the same thing. In addition, AFAIK there are some funny issues in JavaScript when a constructor function returns an object that is not the object bound to `this` (i.e. the new object created by the `new` keyword).
- MatthewPhillips 15y agonew can be useful. I believe instanceof only works with objects created with new.
- strager 15y agoExactly. This is my problem with the `new` syntax. There are still other problems (in my opinion) with the concept of constructor functions. It basically boils down to mixing data (prototype) and code (constructor funciton). Side-effects in a constructor are a big no-no. However, if you want side-effects, you're forced to write your code in a different style. As a (really bad) example, you have an Enemy "class" which must know about enemies adjacent to itself at creation time. Without side-effects (using `new`): var enemy = new Enemy(enemyList); enemyList.push(enemy); // Now enemy is inside of enemyList, // but it's not enforced. I find this // method prone to mistakes. With side-effects (using `new`): var enemy = new Enemy(enemyList); // Now enemy is inside of enemyList; // I wouldn't expect that postcondition! And without constructors, but with side-effects: var enemy = enemyList.createEnemy(); // or var enemy = createEnemy(enemyList); // Now enemy is inside of emptyList The problem here is that an enemy must be part of a list. The classical OO solution is to use constructor parameters. Ideally, I'd just have a function to deal with creation and adding it to the list (like `createEnemy`). In ES5, `enemyList.createEnemy` could be written like this: var enemy = Object.create(Enemy.prototype, { enemyList: { value: this } // Ugh! }); this.push(enemy); Enemy.call(enemy); // Necessary evil if you use standard JS "classes" return enemy; I'd much prefer something like: var enemy = enemyProto { enemyList: this }; // Basically binds the object literal with the enemyProto prototype, returning the modified object. this.push(enemy); // enemy ctor logic here; e.g. Enemy.call(enemy) as above return enemy;