There are loads of functions defined in JavaScript built-in object. For example String has slice(),split() and Array has join() and they can be overridden (though it is a bad practice) by simply using
Array.prototype.join = 'test', Then all the array will lose the join() method
However, as a developer of open source project, in what way should we view this potential changes to the prototype? It will become a problem because it is very likely we will use these functions more or less to achieve some functionalities.
In jQuery, it will keep a copy of some of those methods:
var class2type = {};
var toString = class2type.toString;
var hasOwn = class2type.hasOwnProperty;
But only some of the methods are kept safe, if you read through the source code of jQuery you will notice some String methods are called directly on the String object.
Of course we can always keep a copy of all the methods of built-in JavaScript object but it is so messy. Indeed, it also becomes a problem of execution timing. If the program is executed before the prototype is changed, then it's fine. But it will fail if it is vice versa. So I am more interested to know when jQuery or other libraries they decide to keep a copy of some of the methods, what are their philosophy behind the decision?
Thank you.
As a developer of an open source project, the safest and best thing to do is to pretend that the builtin prototypes are frozen. The practice of extending or modifying them is responsible for far more problems than solutions.
If you need a custom join function, just create it so that it takes a string as the first argument.
function join(string, separator) {
// ...
}
This keeps the prototypes clean and stops you from having to worry about references to overwritten methods.
What you're seeing there in the jQuery example is just aliasing. The methods are being assigned to variables to make them easier to use.
There's no way to code defensively around this, because by the time jQuery loads another script could have already modified the builtin prototypes and the original references would be lost.
Related
I've read a number of questions that state it is unwise to add properties to DOM element objects; and they seem to make a great deal of sense. The best suggestion I came across to accomplish the same end was to use a Weak Map with the DOM node reference as the key.
That led me to wonder about adding properties to function objects. Is that "safe" to do or should another object or map be used for this also. I'm referring to functions on the window object. Can the property names I add clash with names in the function object in the future?
That brings up a related matter I've been trying to understand which is that some claim that the window object is so cluttered up that it ought not to be added to and scripts should be modules now. Modules appears to be more isolated than my limited experience with simple namespaces. Is there anything to be gained through using scripts of type module over just declaring another object and making your functions methods of that object? That object would still be added to the window object.
Thank you.
That led me to wonder about adding properties to function objects. Is that "safe" to do or should another object or map be used for this also. I'm referring to functions on the window object. Can the property names I add clash with names in the function object in the future?
It's not safe in that, if you do it, others could do it too. For example:
// Your code
RegExp.description = 'some description for the constructor!';
setTimeout(() => {
console.log(RegExp.description);
});
// Someone else's code
RegExp.description = "someone else's description";
The only consolation is that it's pretty unlikely for such a thing to happen.
Similarly, it's pretty unlikely for some random English word that one library creates for itself on the window collides with another word that another library creates for itself on the window - but it's not impossible. For that reason
That object would still be added to the window object.
can be seen as slightly less than optimal on huge pages, where collisions are a real possibility.
Is there anything to be gained through using scripts of type module over just declaring another object and making your functions methods of that object?
Yes, see above. If all of your code is in module scripts, there should be no need to put any object onto the window, in most cases. In addition to the above, module scripts often make projects easier to manage because they make all dependencies explicit through the use of import statements. They're also very easily integrated into a build process like Webpack - and build processes allow for all sorts of neat things that aren't easily done otherwise.
semi-novice programmer here (on and off with C++ for years, dabbling with C# mostly with Unity) and when creating objects and methods within objects it's to be expected that that method is a member of that object.
If I create a new object I can access the function with dot notation object.method.
For Javascript it appears that isn't the case?
I read somewhere about it being something like a first class object (not sure what that means) and I have to explicitly say that the method is a part of the object.
So for example in JS
function testObject() {
let x = whatever;
function testMethod() {
}
}
Is a failure, it will not work. testObject has no idea testMethod is a member.
I have to use
this.testMethod = function() {}
before it can be registered.
I just want to be sure cause I can't really find much info even from youtube videos and websites.
I want to fully grasp knowledge of why for once instead of just shrugging my shoulders and just letting it be.
If what I've stated is true can someone give me a heads up why JS is different in this regard? And if there are any other pitfalls with JS objects that I might not notice from a C programmer background.
Thanks.
Edit:
Thanks for the comments. This is also why programming can be such a pain. you look for info, want to delve into it and get such conflicting information. If you google does javascript have classes, first thing you'll see is javascript doesn't have classes (well this is obviously a lie delving deeper). Why say that when it is provably false? Don't care if it's not class based. Don't say there are no classes (Not you specifically just shouting out to the internet).
I know how to declare an object literal and was looking at the youtube video
https://www.youtube.com/watch?v=PFmuCDHHpwk&list=PLTjRvDozrdlxEIuOBZkMAK5uiqp8rHUax&index=2
to brush up on the basics, get my head back in the game and learn a new language. Doubled down on researching just what it all means and it's sticking for once (but I digress). He discusses about Object literals then changes his code into something similar that I presented thag he called a function object.
Is that not a thing?
Am I doing it wrong?
Apparently what I have is not an object?
Though the definition of an object is a group of data in a single unit which includes member variables and methods that work on that data.
Should I forget what I'm seeing and just stick with object literals?
I am learning about object/method chaining in JavaScript and I would like make sure I understand it correctly.
If the following code is an example of JavaScript without object chaining:
var people = helper.getPeople();
var bob = people.find("bob");
var email = bob.getEmail();
and the code below is after applying object chaining:
var email = helper.getPeople().find("bob").getEmail();
Am I to consider object chaining as simply a way to "drill down" into an object, reaching "sub-objects" or properties/methods etc...?
If these two examples of code are supposed to do the same thing, why is a var declaration not required in the object-chained example? I do not understand how the chained statement is the same if no new variables are declared in the process.
I can see the value of saving space and writing the code on one line, and all my research online has shown that this is considered an intuitive, simplified way to write. However, I feel that I am able to read the first example (without object chaining) better. That may just be because I am new to JavaScript, but which example would be considered good coding practice?
Additionally, is the purpose of object chaining merely to reach objects that are not defined in the global scope? A way of reaching local objects?
Thank you for your help!
Am I to consider object chaining as simply a way to "drill down" into an object, reaching "sub-objects" or properties/methods etc...? Is the purpose of object chaining merely to reach objects that are not defined in the global scope? A way of reaching local objects?
It could be. Every of these methods does return another object with methods, that's the secret of chaining. "Drilling down" might be an appropriate wording for some uses, like the one you've shown, where different objects are returned.
However, whether these returned objects are hidden, local "sub-objects", accessible through other means or just created on the fly by that method, or even the original object that returns itself, is dependent on the methods and API design. All options make valid chaining, though.
If these two examples of code are supposed to do the same thing, why is a var declaration not required in the object-chained example? I do not understand how the chained statement is the same if no new variables are declared in the process.
Returning objects that are immediately accessed does not require them to be assigned to any variable. They of course are held in memory somewhere, but don't have an explicit identifier attached to them.
That may just be because I am new to JavaScript, but which example would be considered good coding practice?
Depends. Usually, a good practise is not to create variables if you don't need them. If you are only interested in the email and won't access all the people and bob again, there's no reason to create variables for them.
The readability can be increased by putting each method call on a new line, which is common in JS for chaining:
var email = helper.getPeople()
.find("bob")
.getEmail();
(with various styles of indentation for the subsequent lines)
I have a big object defined in the global scope called global. I would like to dynamically find all the referenced properties under my variable global. That is, all the properties that were accessed during the execution of the code.
I want to do static code analysis to extract all the referenced properties under my variable. I can search for these patterns: global.PROPERTY_NAME AND global[PROPERTY_NAM]. However, what about the complicated cases like these ones
var tmp="PROPERTY_NAME";
global[tmp]
OR
var tmp=global;
tmp.PROPERTY_NAME
and the other ones?
I don't want to get all the variable's properties. I only want a list of the referenced ONES!! the properties that were referenced in my source code only
After your edit:
What you're looking for is JavaScript Proxy objects. Here is a tutorial on how to do this using them.
Proxy objects let you wrap an object and execute a method whenever its properties are accessed. Unfortunately as it currently stands they are not widely supported.
This is currently only way in JavaScript to accomplish this without changing your original global object.
You can turn them on in Chrome by enabling experimental JavaScript in the about:flags tab.
Before your edit:
The feature you're looking for is called reflection, JavaScript supports it well and natively
Here is some code that iterates through an object and gets its properties
for(var prop in global){
if(global.hasOwnProperty(prop)){ //this is to only get its properties and not its prototype's
alert(prop+" => "+global[prop]);
}
}
This is fairly cross-browser. More modern browsers allow you to do this in simpler ways like Object.keys(global) which returns an array containing all its enumerable properties, or Object.getOwnPropertyNames(global) which returns both enumerable and not-enumerable properties.
Due to the dynamic nature of JavaScript you won't achieve that with static code analysis. Think about cases like this:
var prop = document.getElementById('prop').value;
global[prop];
Impossible. The alternative, dynamic analysis, would mean that you modify your global object to log access to its properties, then run the code. This is easily possible in JavaScript but it won't help you either because how would you assure that you have covered every possible access? Especially in a 5 MB JavaScript, there are most likely edge cases that you will oversee.
So, if you can't narrow down your requirement, it won't be possible.
We have been debating how best to handle objects in our JS app, studying Stoyan Stefanov's book, reading endless SO posts on 'new', 'this', 'prototype', closures etc. (The fact that there are so many, and they have so many competing theories, suggests there is no completely obvious answer).
So let's assume the we don't care about private data. We are content to trust users and developers not to mess around in objects outside the ways we define.
Given this, what (other than it seeming to defy decades of OO style and history) would be wrong with this technique?
// namespace to isolate all PERSON's logic
var PERSON = {};
// return an object which should only ever contain data.
// The Catch: it's 100% public
PERSON.constructor = function (name) {
return {
name: name
}
}
// methods that operate on a Person
// the thing we're operating on gets passed in
PERSON.sayHello = function (person) {
alert (person.name);
}
var p = PERSON.constructor ("Fred");
var q = PERSON.constructor ("Me");
// normally this coded like 'p.sayHello()'
PERSON.sayHello(p);
PERSON.sayHello(q);
Obviously:
There would be nothing to stop someone from mutating 'p' in unholy
ways, or simply the logic of PERSON ending up spread all over the place. (That is true with the canonical 'new' technique as well).
It would be a minor hassle to pass 'p' in to every function that you
wanted to use it.
This is a weird approach.
But are those good enough reasons to dismiss it? On the positive side:
It is efficient, as (arguably) opposed to closures with repetitive function declaration.
It seems very simple and understandable, as opposed to fiddling with
'this' everywhere.
The key point is the foregoing of privacy. I know I will get slammed for this, but, looking for any feedback. Cheers.
There's nothing inherently wrong with it. But it does forgo many advantages inherent in using Javascript's prototype system.
Your object does not know anything about itself other than that it is an object literal. So instanceof will not help you to identify its origin. You'll be stuck using only duck typing.
Your methods are essentially namespaced static functions, where you have to repeat yourself by passing in the object as the first argument. By having a prototyped object, you can take advantage of dynamic dispatch, so that p.sayHello() can do different things for PERSON or ANIMAL depending on the type Javascript knows about. This is a form of polymorphism. Your approach requires you to name (and possibly make a mistake about) the type each time you call a method.
You don't actually need a constructor function, since functions are already objects. Your PERSON variable may as well be the constructor function.
What you've done here is create a module pattern (like a namespace).
Here is another pattern that keeps what you have but supplies the above advantages:
function Person(name)
{
var p = Object.create(Person.prototype);
p.name = name; // or other means of initialization, use of overloaded arguments, etc.
return p;
}
Person.prototype.sayHello = function () { alert (this.name); }
var p = Person("Fred"); // you can omit "new"
var q = Person("Me");
p.sayHello();
q.sayHello();
console.log(p instanceof Person); // true
var people = ["Bob", "Will", "Mary", "Alandra"].map(Person);
// people contains array of Person objects
Yeah, I'm not really understanding why you're trying to dodge the constructor approach or why they even felt a need to layer syntactical sugar over function constructors (Object.create and soon classes) when constructors by themselves are an elegant, flexible, and perfectly reasonable approach to OOP no matter how many lame reasons are given by people like Crockford for not liking them (because people forget to use the new keyword - seriously?). JS is heavily function-driven and its OOP mechanics are no different. It's better to embrace this than hide from it, IMO.
First of all, your points listed under "Obviously"
Hardly even worth mentioning in JavaScript. High degrees of mutability is by-design. We're not afraid of ourselves or other developers in JavaScript. The private vs. public paradigm isn't useful because it protects us from stupidity but rather because it makes it easier to understand the intention behind the other dev's code.
The effort in invoking isn't the problem. The hassle comes later when it's unclear why you've done what you've done there. I don't really see what you're trying to achieve that the core language approaches don't do better for you.
This is JavaScript. It's been weird to all but JS devs for years now. Don't sweat that if you find a better way to do something that works better at solving a problem in a given domain than a more typical solution might. Just make sure you understand the point of the more typical approach before trying to replace it as so many have when coming to JS from other language paradigms. It's easy to do trivial stuff with JS but once you're at the point where you want to get more OOP-driven learn everything you can about how the core language stuff works so you can apply a bit more skepticism to popular opinions out there spread by people who make a side-living making JavaScript out to be scarier and more riddled with deadly booby traps than it really is.
Now your points under "positive side,"
First of all, repetitive function definition was really only something to worry about in heavy looping scenario. If you were regularly producing objects in large enough quantity fast enough for the non-prototyped public method definitions to be a perf problem, you'd probably be running into memory usage issues with non-trivial objects in short order regardless. I speak in the past tense, however, because it's no longer really a relevant issue either way. In modern browsers, functions defined inside other functions are actually typically performance enhancing due to the way modern JIT compilers work. Regardless of what browsers you support, a few funcs defined per object is a non-issue unless you're expecting tens of thousands of objects.
On the question of simple and understandable, it's not to me because I don't see what win you've garnered here. Now instead of having one object to use, I have to use both the object and it's pseudo-constructor together which if I weren't looking at the definition would imply to me the function that you use with a 'new' keyword to build objects. If I were new to your codebase I'd be wasting a lot of time trying to figure out why you did it this way to avoid breaking some other concern I didn't understand.
My questions would be:
Why not just add all the methods in the object literal in the constructor in the first place? There's no performance issue there and there never really has been so the only other possible win is that you want to be able to add new methods to person after you've created new objects with it, but that's what we use prototype for on proper constructors (prototype methods btw are great for memory in older browsers because they are only defined once).
And if you have to keep passing the object in for the methods to know what the properties are, why do you even want objects? Why not just functions that expect simple data structure-type objects with certain properties? It's not really OOP anymore.
But my main point of criticism
You're missing the main point of OOP which is something JavaScript does a better job of not hiding from people than most languages. Consider the following:
function Person(name){
//var name = name; //<--this might be more clear but it would be redundant
this.identifySelf = function(){ alert(name); }
}
var bob = new Person();
bob.identifySelf();
Now, change the name bob identifies with, without overwriting the object or the method, which are both things you'd only do if it were clear you didn't want to work with the object as originally designed and constructed. You of course can't. That makes it crystal clear to anybody who sees this definition that the name is effectively a constant in this case. In a more complex constructor it would establish that the only thing allowed to alter or modify name is the instance itself unless the user added a non-validating setter method which would be silly because that would basically (looking at you Java Enterprise Beans) MURDER THE CENTRAL PURPOSE OF OOP.
Clear Division of Responsibility is the Key
Forget the key words they put in every book for a second and think about what the whole point is. Before OOP, everything was just a pile of functions and data structures all those functions acted on. With OOP you mostly have a set of methods bundled with a set of data that only the object itself actually ever changes.
So let's say something's gone wrong with output:
In our strictly procedural pile of functions there's no real limit to the number of hands that could have messed up that data. We might have good error-handling but one function could branch in such a way that the original culprit is hard to track down.
In a proper OOP design where data is typically behind an object gatekeeper I know that only one object can actually make the changes responsible.
Objects exposing all of their data most of the time is really only marginally better than the old procedural approach. All that really does is give you a name to categorize loosely related methods with.
Much Ado About 'this'
I've never understood the undue attention assigned to the 'this' keyword being messy and confusing. It's really not that big of a deal. 'this' identifies the instance you're working with. That's it. If the method isn't called as a property it's not going to know what instance to look for so it defaults to the global object. That was dumb (undefined would have been better), but it not working properly in that scenario should be expected in a language where functions are also portable like data and can be attached to other objects very easily. Use 'this' in a function when:
It's defined and called as a property of an instance.
It's passed as an event handler (which will call it as a member of the thing being listened to).
You're using call or apply methods to call it as a property of some other object temporarily without assigning it as such.
But remember, it's the calling that really matters. Assigning a public method to some var and calling from that var will do the global thing or throw an error in strict mode. Without being referenced as object properties, functions only really care about the scope they were defined in (their closures) and what args you pass them.