Backbone.js source read-through - javascript

I'm reading through the Backbone.js source and am somewhat confused by these lines (L230-238, v0.5.3)
unset : function(attr, options) {
if (!(attr in this.attributes)) return this;
options || (options = {});
var value = this.attributes[attr]; // ?: value appears to be unused (?)
// Run validation.
var validObj = {};
validObj[attr] = void 0; //void 0 is equivalent to undefined
if (!options.silent && this.validate && !this._performValidation(validObj, options)) return false;
Am I crazy or does the last line run a validation against a hash object with a single undefined attribute?
It seems like the validation is intended to run on an instance of the Model object with the attribute-to-be-unset removed.
Current source on github with lines highlighted

you're correct in your assessment of what it does, but that's the intended functionality.
when you call unset, you can only tell it to unset one attribute at a time: model.unset("myAttr")
when unsetting, validation is called to make sure the model will be put into a valid state. if the attribute being set to undefined will cause the model to be invalid, the unset fails. if it is valid for the attribute to be undefined, the attribute is removed from the model.
the reason it passes a "hash object with a single undefined attribute" is that all objects in javascript as "hash objects" - key value pairs, or associative arrays. it doesn't matter how you get an object, it is an associative array.
an object with one empty attribute named after the model's attribute that is being unset, is created in lines 236-237. this is so that monkeying with the object passed into the validate method won't change the state of the model itself.
hope that helps explain things.

Related

value is undefined for some users, empty string for others

I have a form that on submission packages the data into an ajax format and sends to a coldfusion script via ajax. A bug crept up that affected from two computers but not mine and another. I tracked it down to a struct key not existing. When I do a console log of the packaged json data, we all see the struct key before it's passed. For me, its value is an empty string. For others, it says undefined. And because of that, coldfusion appears to drop the key from the struct after receiving it, which is what caused the initial issue we had. Once that was determined it was a simple fix.
The struct key is assigned a value from a jquery object, which is a SELECT element (no multiple). My structure would look something like this:
var fields = {
myVar: $('#import_me').val()
};
What I'm trying to figure out is why, when nothing is selected, does it assign an empty string for me but will be undefined for my colleagues? We're on the same browser and version.
Would this give me more consistent results instead?
$('#import_me option:selected').val()
Does this work for you?
A fallback:
var fields = {
myVar: $('#import_me').val() || ''
};
It should set an empty string as fallback if there is no val()
But possibly this is better:
Check the variable and set it to empty string if it is undefined.
var fields = {
myVar: $('#import_me').val()
};
if (fields[myVar] === undefined) {
fields[myVar] = "";
}

Shorthand computed properties

Can anyone please explain why these don't evaluate to the same thing?
Ember.ArrayController.extend({
maxProducts: 5,
hasMaxProducts: function () {
return this.get('model.length') === this.get('maxProducts');
}.property('model.length'),
shorthandHasMaxProducts: Ember.computed.equal('model.length', 'maxProducts')
});
I'm using the hasMaxProducts property in a handlebars template successfully, and if I try switching to the shorthandHasMaxProducts property, I don't get the same results, nor does it seem that this property ever updates. This should happen when I add another model to the array collection. I've also tried computing with:
Ember.computed.equal('model.[]', 'maxProducts')
Ember.computed.equal('model.[].length', 'maxProducts')
The second argument of Ember.computed.equal cannot be a property name, it has to be a plain javascript value, so a string, integer, boolean etc.
http://emberjs.com/api/#method_computed_equal

Equivalent of Python's KeyError exception in JavaScript?

I am trying to access a certain member in a JavaScript object. In order to do this, I need to try out a couple of key values.
For example, Object['text/html'] which will give me an export link for a HTML document. However, not every object of this type will have a text/html key pair value.
In Python I would solve this problem using a Try-Catch block, with the KeyError exception. If I can do something similar in javascript, as in use an exception in a Try-Catch block, that would be great.
However, if alternatives exists instead of try catch blocks, that do achieve the same end goal, I would like to know about them as well.
EDIT:
I would prefer to use an exception over using functions. I do this because the text/html key might not be there, but it should be there. An exception seems more appropriate for this scenario
Javascript doesn't generate an exception when reading or writing a property that doesn't exist. When reading it, it just returns undefined. When writing it, it just creates the property.
You could create your own function that tests to see if the property exists and throws an exception if it does not (but you'd have to call that function whenever), but JS doesn't make an exception out of that on it's own like you are asking for.
If you want to test if a key exists on an object in javascript, you can use this construct with the in operator:
var obj = {};
var key = "test";
if (key in obj) {
// key exists
} else {
// key doesn't exist
}
If you try to read a key that doesn't exist, you will get undefined as the value.
var obj = {};
var value = obj.test;
alert(value === undefined);
The in operator does a better job of telling you whether the key exists that testing for undefined because undefined is a legal value for a key that exists.
In many cases, where you control the values that the keys have and a key that is present will never have a falsey value, you can also just check if the key has a truthy value:
var obj = {};
var obj.test = "hello";
if (obj.test) {
// key exists and has a truthy value
}
If you want to make sure that the object itself has the property and not any prototype that it is inheriting from, then you can do this:
var obj = {};
var obj.test = "hello";
if (obj.hasOwnProperty(test)) {
// key exists on the object itself (not only on the prototype)
}
Read this!
The accepted answer is correct however omits some points.
1) Accessing nested object
Like someone pointed out in the comment, Javascript returns undefined when the key doesn't exists in the object.
However, if you need to access an object inside an object (or an Array, or a function), well this break.
let a = {};
let userName = 'js'
let data = a.response[userName];
Cuz you will received actually a TypeError, basically because we are trying to read a property of undefined, which doesn't have any.
VM187:2 Uncaught TypeError: Cannot read properties of undefined (reading 'js')
at <anonymous>:2:22
2 Answering the question
The Python principle "Ask forgiveness not permission" - explain is actually for the most part working well in Javascript (and PHP, you didn't ask but well..). There are for sure some difference, or some situation where the difference is important, but for most use cases is the same
So this is how you would do it:
try {
let data = a.key1.key2['whatever'].nested.damn.object;
console.log(data)
} catch (error) {
let data = "noope";
console.log(data);
}
As you can see, in Javascript you don't really care about the error type, (for the most part, sure other situation you should case). Is almost like anything is in a Python's
try:
a = "hello" + 1 + {} + [] # crazy stuff here
except BaseException as bleh:
print(str(bleh))
Documentatin
MDN Working with objects
How do I check if an object has a key in JavaScript? [duplicate]

Does Javascript have get/set keywords like C#?

I'm working with XULRunner and came across the following pattern in a code sample:
var StrangeSample = {
backingStore : "",
get foo() { return this.backingStore + " "; },
set foo(val) { this.backingStore = val; },
func: function(someParam) { return this.foo + someParam; }
};
StrangeSample.foo = "rabbit";
alert(StrangeSample.func("bear"));
This results in "rabbit bear" being alerted.
I've never seen this get/set pattern used in Javascript before. It works, but I can't find any documentation/reference for it. Is this something peculiar to XUL, a recent language feature, or just something I missed? I'm puzzled because I was specifically looking for something like this a few months ago and couldn't find anything.
For reference, removing "get" or "set" results in a syntax error. Renaming them to anything else is a syntax error. They really do seem to be keywords.
Can anyone shed some light on this for me, or point me towards a reference?
As suggested by Martinho, here are some links explaining the getter/setters in JS 1.5:
http://ejohn.org/blog/javascript-getters-and-setters/
http://ajaxian.com/archives/getters-and-setters-in-javascript
Be aware though, they don't seem to be supported in IE, and some developers have (legitimate) concerns about the idea of variable assignment having side-effects.
get/set are not reserved keywords as Daniel points out. I had no problem creating a top-level functions called "get" and "set" and using the alongside the code-sample posted above. So I assume that the parser is smart enough to allow this. In fact, even the following seems to be legitimate (if confusing):
var Sample = {
bs : "",
get get() { return this.bs; },
set get(val) { this.bs = val; }
}
According to Mozilla, they are not in ECMAScript.
JavaScript Setters And Getters:
Usually the setter and getter methods follow the following syntax in JavaScript objects. An object is created with multiple properties. The setter method has one argument, while the getter method has no arguments. Both are functions.
For a given property that is already created within the object, the set method is typically an if/else statement that validates the input for any time that property is directly accessed and assigned later on via code, a.k.a. "set". This is often done by using an if (typeof [arg] === 'certain type of value, such as: number, string, or boolean') statement, then the code block usually assigns the this.(specific)property-name to the argument. (Occasionally with a message logging to the console.) But it doesn't need to return anything; it simply is setting the this.specific-property to evaluate to the argument. The else statement, however, almost always has a (error) message log to the console that prompts the user to enter a different value for the property's key-value that meets the if condition.
The getter method is the opposite, basically. It sets up a function, without any arguments, to "get", i.e. return a(nother) value/property when you call the specific-property that you just set. It "gets" you something different than what you would normally get in response to calling that object property.
The value of setters and getters can be easily seen for property key-values that you don't want to be able to be directly modified, unless certain conditions are met. For properties of this type, use the underscore to proceed the property name, and use a getter to allow you to be able to call the property without the underscore. Then use a setter to define the conditions by which the property's key-value can be accessed and assigned, a.k.a. "set". For example, I will include two basic setters and getters for this object's properties. Note: I use a constant variable because objects remain mutable (after creation).
const person = {
_name: 'Sean';
_age: 27;
set age(ageIn) {
if (typeof ageIn === 'number') {
this._age = ageIn;
}
else {
console.log(`${ageIn} is invalid for the age's key-value. Change ${ageIn} to/into a Number.`);
return 'Invalid Input.';
}
},
get age() {
return this._age;
},
set name(nameIn) {
if (typeof nameIn === 'string') {
this._name = nameIn;
} else {
console.log(`Change ${nameIn} to/into a(ny) String for the name's
key-value.`);
return 'Invalid Input.';
}
},
get name() {
return this._name;
}
};
Where it gets interesting is when you try to set/assign a new key-value for the _age property, because it has to meet the if conditional in order to be successfully assigned, meaning not all assignments are valid, etc.
person.age = 'twenty-eight'; /* output: twenty-eight is invalid for the
age's key-value. Change twenty-eight to/into a Number. */
console.log(person.age); // output: 27 (twenty-eight was never assigned)
person.age = 28; // output: none
console.log(person.age); // output: 28
Note how I was able to access the person._age property via the person.age property thanks to the getter method. Also, similar to how input for age was restricted to numbers, input for the name property is now restricted/set to strings only.
Hope this helps clear things up!
Additionally, some links for more:
https://johnresig.com/blog/javascript-getters-and-setters/
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get
https://www.infragistics.com/community/blogs/infragistics/archive/2017/09/19/easy-javascript-part-8-what-are-getters-and-setters.aspx

What does this mean?

function fkey(a) {
a || (a = {});
if (!a.fkey) a.fkey = $("input[name='fkey']").attr("value");
return a
}
I guess a is actually a function, but how to understand (!a.fkey) ?
a is an object in this case, it's setting the .fkey property on it if it isn't set (or is falsy) already.
For SO chat, this allows the fkey input to either be provided or gotten from the page, it's a hidden input at the bottom of your page, populated with a value used to authenticate your request and such.
Currently it's always pulling from the DOM, so really this function just adds the property, it would leave it alone if it were provided though.
a is not a function, it's an object.
The a.fkey is accessing a member of the a object. The ! in front means that if the member does not exist or the value is falsy, the expression evaluates to true and the fkey member is set to $("input[name='fkey']").attr('value');, which can also be accomplished with .val() instead of .attr('value')
The function you posted adds a member named fkey to a if it did not already exist. The !a.fkey part essentially means "does not already exist" (this works because once assigned, the member does not evaluate to false).
The function takes an object and adds an fkey property to it, which will be the value of
<input name="fkey"> field.
For example:
<input name="fkey" value="WATCH ME HERE">
var temp = {}; // make a new object
fkey(temp); // expand it with fkey's value
alert(temp.fkey); // WATCH ME HERE

Categories