I am wondering if I can modify the parameter in the function?
Objects and arrays are passed by reference and changes to the argument you pass to a function will affect the original. All other types behave like they are passed by value and you cannot change the original.
Javascript does this automatically - you cannot specify that something be passed by value or by reference like you can in some other languages. If you want something passed by reference, put it in an array or object and pass the array/object.
Example 1 (passing an object):
function myFunc(myObject) {
// this changes the original object
myObject.ready = true;
}
var obj = {ready: false;};
myFunc(obj);
// obj.ready == true - value is changed
Example 2 (passing a string):
function hello(str) {
str = str + " and goodbye";
alert(str);
}
var greeting = "Hello";
hello(greeting);
// greeting == "Hello" - value is unchanged
Example 3 (passing a string in an object):
function hello(obj) {
obj.str = obj.str + " and goodbye";
alert(obj.str);
}
var o = {greeting: "Hello"};
hello(o);
// o.greeting == "Hello and goodbye" - value is changed
Example 4 (passing a number):
function hello(num) {
num++;
alert(num);
}
var mynum = 5;
hello(mynum);
// mynum == 5 - value is unchanged
Note: One thing that is sometimes confusing is that strings are actually passed by reference (without making a copy), but strings in javascript are immutable (you can't change a string in place in javascript) so if you attempt to modify the string passed as an argument, the changed value ends up in a new string, thus the original string is not changed.
I think you are meaning to ask "Is it possible to change a value passed parameter to a referenced one?"
Javascript is, by nature, a pass by reference language for objects. Primitives like numbers, booleans, and strings are passed by value. If your thinking about how PhP (or a few others) can change the pass by reference or value modifier (IE function passByRef( &refVar ) ) this is not possible with javascript. There is a good post here about how sometimes javascript can be a little more indifferent while passing certain objects and what you might expect, vs what actually happens if it helps.
Is JavaScript a pass-by-reference or pass-by-value language?
Related
I'm using the internationalization library l10n.js and it appears you cannot pass a value to the library to tell it what language you want to run translations on as it attempts to get the value from the clients browser; so I have been told if you actually want to set the locale you would need to do something like:
String.locale = 'en-GB';
In my case I am doing:
String.locale = $('html').attr('lang');
...right at the top of the file.
This works, however in PhpStorm I get the warning that:
Value assigned to this primitive will be lost
I checked this question out and understand why they got the warning, but am unsure in my instance - is it basically just telling me that the current value of String.locale will be lost?
It looks like a false alarm of the PhpStorm type inference system.
The String is not a primitive in JavaScript language. It is safe to assign a value to the property of the String here because of the String function is an object.
I suppose that the key idea of the Value assigned to this primitive will be lost could be described with the code:
> var primitive = "somestring";
> primitive.someprop = 3;
3
> primitive.someprop;
undefined
In JavaScript there are 5 primitive types: undefined, null, boolean, string and number. Primitives are not objects and they have no properties. If JavaScript detects an attempt to assign a property to a primitive it will indeed coerce the primitive to an object. But this new object has no references and will immediately become fodder for garbage collection. Therefore a value assigned to primitive will be lost. link
PHPStorm warns you about creating objects of String. Each of new instance will not contain locale variable as it's not declared in String.prototype. The code below should explain it.
var index = 1;
function test(value) {
document.body.innerHTML += index++ + " " + value;
document.body.innerHTML += "</br>";
}
test(String.locale); // 1 - check if locale exists
String.locale = "locale";
test(String.locale); // 2 - should return "locale"
String.prototype.locale = "other locale";
test(String.locale); // 3 - should strill return "locale"
test(String.prototype.locale); // 4 - should return "other locale"
test("".locale); // 5 - "other locale"
test(String("").locale); // 6 - "other locale"
test((new String("")).locale); // 7 - "other locale"
String.locale = "locale";
test((new String("")).locale); // 8 - still "other locale", "locale" variable is not used when creating objects from "String" thus it's lost in all instances of this constructor
NOTE:
It seems PHPStorm warns about those primitives only:
Number
String
Boolean
null (not Null, null)
It's IDE specific behavior. It doesn't notify about custom objects.
EDIT
After some research I understood I was wrong. It seems my answer wasn't related to the PHPStorm warning.
When you create a primitive variable and set it's property like so: primitive.locale = "en-GB" and try to access it by primitive.locale it will be undefined. That's what the warning is trying to tell you.
What I said about primitives still stand, PHPStorm notifies you only about Number, String, Boolean and null.
Check code below:
var someBoolean = true;
someBoolean.locale = "en-GB";
document.body.innerHTML += someBoolean.locale;
document.body.innerHTML += "</br>";
var someString = "test";
someString.locale = "en-GB"
document.body.innerHTML += someString.locale;
Or, as in my case, you can trigger this error like so:
const testObj = {};
testObj.name.first = 'jane';
It doesn't like the fact that the 'name' property has yet to be defined before we have started assigning stuff to it.
I am doing a simple javascript problem where I have to pass an array through a function and have the array reassigned a different value. How come when I pass through an array (or even any variable) I have to specifically reassign the array in order for it to change? Can't I just use the code in the function to use the parameter to do that for me? Here's my code:
<script>
var str = 'this is my sentence';
//Write a function called reverse that takes is given str as it's only argument and returns that string after it's been reversed
function reverse(x) {
x = x.split('').reverse().join('');
return x;
}
//returns with the text reversed, but str is still 'this is my sentence' and not the reversed version
</script>
You have to actually call the reverse function. Your code works once you add str = reverse(str);
<script>
var str = 'this is my sentence';
//Write a function called reverse that takes is given str as it's only argument and returns that string after it's been reversed
function reverse(x) {
x = x.split('').reverse().join('');
return x;
}
str = reverse(str); //Call the function
window.alert(str); //show an alert box to view reversed string
</script>
EDIT
It seems the brunt of his question is [Why do] I have to specifically reassign the array in order for it to change?.
The argument is a primitive and with primitives, javascript passes by value. Meaning that the called functions' parameter will be a copy of the callers' passed argument. It is not the same item.
The alternative would be pass by reference in which case the called functions' parameter will be the same object as the caller's passed argument. In this case, changes occurring inside the function on the object passed as a parameter will be 'available' outside the function - because it's the same object. This is how Javascript passes objects.
In Javascript, a string can be either an object or a primitive depending on how you create it:
var str = "I'm a String primitive"; //This is a primitive
var str = new String("I'm a String object"); //this is an object
I've previously asked a fairly similar question, and with this answer, I know it's possible to make objects that return strings when placed inside other strings. This would be some code based on that answer which would allow the object to have a custom string return value:
function myString(value) {
this.String = value;
}
myString.prototype.toString = function() {
return this.String;
}
var strObj = new myString('Foo');
//>> strObj
//<< myString {String: "Foo", toString: function}
//>> strObj+''
//<< "Foo"
//What I want in addition to this:
//>> +strObj
//<< 42
I originally got the idea for that original question by seeing the effects of Date objects within strings. So, since there's another feature of Date objects that could be quite useful, I'd like to know if there's a way for me to do the same thing as Date objects do when used in an expression (being converted to a number):
+new Date(); //1401414068943
I'd like my myString object to do the same. I've tried to continue the mindset of the prototype toString in the object, but although there is a JS method to convert to strings, there's no method - only a native function - to convert non-numbers to strings.
So is it possible for me to do this 'automatic object-to-number conversion' for my own objects, or is this some kind of sorcery only available to Date because it's native to JS?
I'd like the syntax to then be
var strObj = new myString('Foo', 42);
if that's possible.
I believe the prototype method you are looking for that handles object to numeric conversion is Object.prototype.valueOf()
It can be altered or customized just as you are altering toString()
Be aware that this sort of thing can be considered bad style when it may confuse other programmers (including yourself at a future date) as standard conversions can be redefined to behave differently than expected.
toString is the method that is invoked when an object is used in a string context (more exactly, when ToString is called on it). And yes, there is a similar method that is invoked when an objet is used in a numeric context (ToNumber): valueOf. If either doesn't exist, the other is used, for details see the DefaultValue algorithm.
function MyHybrid(str, num) {
this.string = str;
this.value = num;
}
MyHybrid.prototype.toString = function() {
return this.string;
};
MyHybrid.prototype.valueOf = function() {
return this.value;
};
var hybrid = new MyHybrid('Foo', 42)
String(hybrid) // "Foo"
Number(hybrid) // 42
However, it must be noted that strObj+'', which you have used for a conversion into a string, does not call ToString. The + operator can both act on numbers and strings, and therefore does only call ToPrimitive without a type hint - in which case valueOf is preferred (unless it is a Date object). hybrid+'' is equivalent to 42+'' and will yield "42".
This question already has answers here:
Object.prototype.valueOf() method
(2 answers)
Closed 9 years ago.
What does ({}).valueOf.call(myvar) do?
it converts any value to an object (an object remains unchanged, a primitive is converted to an instance of a wrapper type).
My question is how?Can someone give The longer answer how this is done behind the scene.Since valueOf() method is meant to return primitive values not object .
console.log{name:"sameer"}.valueOf() //returns an object but cant be displayed since toString() method will be called by js so [object Object] gets displayed which is a string ,how to display the exact return value from valueOf() method .Is there a way?
Hello again! Once more, we face the mighty opponent. Before we begin, let's dispel one false thought:
valueOf() method is meant to return primitive values not object .
Not accurate. valueOf returns an object if a primitive value was passed to it. If you do valueOf(object), you'd get the same object: valueOf(object) === object. You can trivially see that:
var obj = {};
obj.valueOf() === obj; //true
Now, for the more interesting question: How is valueOf defined? Let's look at the ES5 specification along with the v8 and spidermonkey sources.
valueOf (spec, v8, spidermonkey):
function ObjectValueOf() {
return ToObject(this);
}
As we can see, it simply returns ToObject, as defined in the spec. The rabbit hole emerges.
ToObject (spec, v8, spidermonkey)
function ToObject(x) {
if (IS_STRING(x)) return new $String(x);
if (IS_SYMBOL(x)) return new $Symbol(x);
if (IS_NUMBER(x)) return new $Number(x);
if (IS_BOOLEAN(x)) return new $Boolean(x);
if (IS_NULL_OR_UNDEFINED(x) && !IS_UNDETECTABLE(x)) {
throw %MakeTypeError('null_to_object', []);
}
return x;
}
Jackpot. We can see the entire flow here. If it's a string, number, boolean, etc return a wrapper ($String and $Boolean and the likes represent the actual String or Number; see here); if it's an invalid argument, throw an error; otherwise, return the argument.
The spidermonkey source for that one goes deeper down the rabbit hole. It defines ToObject as such:
JS_ALWAYS_INLINE JSObject *
ToObject(JSContext *cx, HandleValue vp)
{
if (vp.isObject())
return &vp.toObject();
return ToObjectSlow(cx, vp, false);
}
So if it's not an Object, call ToObjectSlow. Buckle up Alice, there'll be C++. We need to take a look at what ToObejctSlow does:
JSObject *
js::ToObjectSlow(JSContext *cx, HandleValue val, bool reportScanStack)
{
if (val.isNullOrUndefined()) {
...error throwing magic here...
return NULL;
}
return PrimitiveToObject(cx, val);
}
More indirection after looking whether the argument was null or undefined. The finale is here:
JSObject *
PrimitiveToObject(JSContext *cx, const Value &v)
{
if (v.isString()) {
Rooted<JSString*> str(cx, v.toString());
return StringObject::create(cx, str);
}
if (v.isNumber())
return NumberObject::create(cx, v.toNumber());
JS_ASSERT(v.isBoolean());
return BooleanObject::create(cx, v.toBoolean());
}
Pretty much the same as the v8 version, only with different taxonomy.
Now, as I said before, I think your question has more to do with the medium of representing the object you see. Firebug and chrome's devtools are more than apt at displaying an object. However, if you try to alert it, you'll see the unfortunate [object Object], because that's what ({}).toString() gives you (since it gives out a string of the form [object InternalClassName], again, as we've seen before).
As a bonus, try console.dir({foo : 'bar'})
To answer your first question
JavaScript has two main variable category types, primitives and Objects. You will often hear this, in JS everything is an Object. That is not entirely accurate. There are also primitive data types, which do nothing but hold values.
They have no methods and they are not instances of a wrapper type. So before you can call any method on them, they need to be converted to an object of the wrapper type. In JavaScript this conversion is automatic and it is called auto-boxing.
Allow me to demonstrate:
var firstString = "Test";
typeof firstString == "string"; // true
var secondString = new String("Test");
typeof secondString == "string"; // false
secondString.prototype.toString.call// [object String];
Notice what happens. There are actually two types above. One is string and the other one is [object String]. This tells you two things: secondString instanceof String is true. That is a wrapper type. Inside the core language you are seeing that String inherits from Object.
But the first string is just a memory reference, nothing more. When you call methods like firstString.replace(), firstString is automatically converted to its wrapper type. This is autoboxing.
The above behaviour stands for the following pairs:
Number autoboxing
var x = 5; var y = new Number(5);,
Boolean autoboxing
var x = false; var y = new Boolean(false);
RegExp autoboxing
var x = new RegExp("etc"); var y = /etc/;
Object.prototype.valueOf
The valueOf method is defined for any Object. In order for it to be called, it will convert all primitive types to their wrapper types and will leave existing objects unchanged. Now it will simply return the value held in the Object reference. So it's pretty simple and it is a way to FORCE AUTOBOXING. You are forcing the conversions I was mentioning earlier.
To answer your second question
Displaying the unfiltered result is simple. Use console.dir().
Look here.
({}).valueOf.call(myvar);
It is the exact equivalent of Object.prototype.valueOf.call(myVar);. Now you already know what valueOf does.
Assuming you know the way Function.prototype.call works, your statement will call the valueOf method in the scope of the object you pass as a this argument to Function.prototype.call(the first parameter is the this object reference).
var myvar = {
"name": "name"
};
({}).valueOf.call(myVar);
// is equivalent to
myVar.valueOf();
So..
I am passing data to a function that handles strings and numbers differently.
I would LIKE to be able to pass an array of values and detect what the types of each value is.
row[0] = 23;
row[1] = "this is a string... look at it be a string!";
row[2] = true;
$.each(row, function(){
alert(typeof(this));
//alerts object
});
Is it possible to detect the "actual" datatypes in a given row?
Try
var row = [ 23, "this is a string", true ];
$.each(row, function (index,item) {
alert(typeof(item));
});
// Alerts "number", "string", "boolean"
Whenever possible I try to avoid using "this" in callbacks and using explicit arguments is usually clearer and more predictable.
#Rich suggested the best possible solution - use values passed to callback as arguments. Quote from jQuery doc:
The value can also be accessed through the this keyword, but Javascript will always wrap the this value as an Object even if it is a simple string or number value.
this.valueOf() might help you to "go back" to primitive value. But still - in that specific example it's better to use values passed as function arguments.