I read that in JS stings are immutable, and even though the default for JS appears to be "pass by reference", passing the same string around a recursive hierarchy will not append to the same string but rather create copies.
My scenario requires for a single string object to be created once, and passed around in a very deep and long hierarchy of recursive and other functions, so how can I achieve this? I am a C++ guy, and in C++ it is quite easy... just pass by reference and all functions work on the same bit of string.
You can simulate pass by reference for primitive values using a wrapper object. This involves altering your functions to be aware of that:
function append(strWrapper,n) {
if (n <= 0) {
return strWrapper;
} else {
strWrapper.val += n;
return append(strWrapper, n-1);
}
}
console.log(append({ val : '' }, 9).val); // 987654321
Of course the wrapper object could turn into a wrapper class if you are so inclined.
*JS does pass by reference only for objects, not for primitive values
You can pass Array/String Objects as they are passed by reference , something like below code to find subsequences i have passed array of string (output) to store all subsequences in which is passed in every call
`
function subsequence( input, output){
if(input.length==0)
{
output[0]="";
return 1;
}
let smallStr = input.substr(1);
let smallerSeqSize = subsequence(smallStr,output);
for(let i=0;i<smallerSeqSize;i++){
output[smallerSeqSize+i] = input[0]+output[i];
}
return 2*smallerSeqSize;
}
function main(){
let input = "abc";
let output = new Array("")
let sizeOutput = subsequence(input,output);
console.log(output)
}`
Related
I know the implementation of how to pass infinite parameters in a function in javascript.
But how to accepts any number of objects as a parameter in function?
I have this:
function merge<T>(objA:T, objB: T){
return Object.assign(objA, objB);
}
so that I can do like this:
console.log(`${mergeObject2.age}, ${mergeObject2.name}`);
But how to declare a function if that number of objects is not known..?
for example this:
const mergeObject2 = merge({name: 'Niels'}, {age :39}, {hobby: 'all'});
Thank you.
so if I do it like this:
const mergeObject2 = merge({name: 'Niels'}, {age :39} );
console.log(`${mergeObject2.age}, ${mergeObject2.name}`);
then the output is of course:
39, Niels
But how to do it if you have more objects..?
Fundamentally, if you want to accept N parameters in TypeScript, the varying parameters will all have to have the same type. (It can be a union type, though.) For instance:
function myFunction(a: boolean, b: string, ...rest: Array<number | string>) {
// ...
}
(Array<number | string> can also be written (number | string)[].)
That function requires at least two arguments (a boolean and a string) followed by any number of number or string arguments. Note how the "rest" of the parameters are bundled up in an array, which is why they have to have the same type (number | string in the example). Of course, once you're dealing with one specific element from that array, you can use if to narrow its type.
If you don't need any fixed parameters (a and b in the example), just start with the rest parameter.
If you want to use Object.assign in the implementation, you'll need to make the first one required (or hardcode Object.assign's first argument). So your merge might be:
function merge<T extends object>(target: T, ...sources: T[]): T {
return Object.assign(target, ...sources);
}
const mergeObject2 = merge({name: "Niels"}, {age: 39}); // ¹
console.log(`${mergeObject2.age}, ${mergeObject2.name}`);
Playground link
That's basically just Object.assign but with the types slightly more restricted (I think), though.
¹ You might want to put a {} at the beginning to avoid modifying the {name: "Neils"} object.
You can make use of arguments object available in ES5.
It's just like a variable with type array, and is accessible inside a function.
It contains the values of all the arguments passed to that function.
function a(){
let sum = 0;
for(let i=0;i<arguments.length;i++){
sum += arguments[i];
}
console.log(sum);
}
a(1,2,3);
In your case to copy all objects into one, you can do something like this:
function a(){
let finalObj = {};
for(let i=0;i<arguments.length;i++){
finalObj = {...finalObj,...arguments[i]};
}
console.log(finalObj);
}
a({id:1},{name:"sam"},{age: 25});
_ .memoize = function(func) {
var hash = {};
return function() {
var arg = JSON.stringify(arguments);
if (hash[arg] === undefined) {
hash[arg] = func.apply(this, arguments);
}
return hash[arg];
};
};
Hello,
I am trying to implement the memoize underscore function. I have a question regarding to JSON.stringify.
In the if statement where it checks if the arg already exist or not in the hash. Why using JSON.stringify make it possible to check wether the input arg exist or not in the hash. I mean if we pass the arguments array without converting them using JSON.stringify, then we cannot check because we are passing an entire array. However, when using JSON.stringify, it makes it work. So how does JSON.stringify make it possible to check ?
The hash is a JavaScript object, which uses strings as keys. You cannot use an array (or array-like, in the case of arguments) there, so it needs to be converted to a string.
If no custom conversion is done, then the default serialisation would be "[object Arguments]" for any value of arguments. This is not unique and will not work with the intention of memoization.
var hash = {};
var i = 0;
//a naive function that takes anything and puts it in a hash with a unique value
function populateUnique() {
hash[arguments] = "Hello" + i;
i++;
}
populateUnique("a");
populateUnique("b");
populateUnique("c", "d", "e");
console.log(hash); //only shows the last thing, as it it's always overridden.
This implementation chooses to employ JSON.stringify because it is quite straight forward - you could implement a custom serialisation function, but there is already one provided, so this is the simplest way to do it.
Should be noted that JSON.stringify is not bulletproof. It is easy to use and covers a lot of cases, but may blow up, for example, if you have circular references:
var foo = {};
foo.bar = foo;
JSON.stringify(foo);
Since the memoize function does not control what will be passed in as arguments, it's possible that one of them, that is normally perfectly valid, will throw an error.
Another problem is if any of the arguments has its own toJSON method - this will be used for serialization, so you could end up in an interesting situation:
var a = 42;
var b = {
firstname: "Fred",
lastname: "Bloggs",
id: 42,
toJSON: function() { return this.id }
}
console.log(JSON.stringify(b));
console.log(a == JSON.stringify(b));
It's because only strings can be used as keys in javascript objects.
For example:
var key = {a:1};
var map = {};
map[key] = 1;
// {'[object Object]': 1}
This will result in every arguments combination being saved in the same key.
Using JSON.stringify transform the arguments list in an unique string that can in turn be used as an unique object key.
var key = {a:1};
var map = {};
map[JSON.stringify(key)] = 1;
// {'{"a":1}': 1}
This way, every time you call the function with the same arguments, JSON.stringify will return the same unique string and you can use that to check if you already have a cached result for that set of arguments, and if so, returning the cached value.
I have been studying JavaScript algorithms and Big O for interviews. I was told that knowing the runtimes of built-in methods, such as Object.prototype.hasOwnProperty and Array.prototype.map, is important.
What is a simple way to view the source code for these functions in node.js? I have a local copy of node.js, and I tried to search for these methods in my text editor, but it's not as straightforward as I thought.
Object.prototype.hasOwnProperty()
From a Javascript interview point of view, I would think you just need to fully understand what obj.hasOwnProperty() does at the Javascript level, not how it's implemented inside of V8.
To do that, you should fully understand this little snippet:
function MyConstructor() {
this.methodB = function() {}
}
MyConstructor.prototype = {
methodA: function() {}
};
var o = new MyConstructor();
log(o.hasOwnProperty("methodA")); // false
log(o.hasOwnProperty("methodB")); // true
o.methodA = function() {}; // assign "own" property, overrides prototype
log(o.hasOwnProperty("methodA")); // true
This is because .hasOwnProperty() looks only on the object itself and not on the prototype chain. So properties which are only on the prototype chain or do not exist at all will return false and properties which are directly on the object will return true.
Array.prototype.map()
A polyfill in Javascript for Array.prototype.map() is here on MDN which will show you exactly how it works. You can, of course, do the same type of search I did above in the Github repository to find the .map() implementation too if you want.
Array.prototype.map() is pretty simple really. Iterate over an array, calling a function for each item in the array. Each return value of that function will be used to construct a new array that will be returned from the call to .map(). So, conceptually, it's used to "map" one array to another by calling some transform function on each element of the original array.
In the simplest incarnation, you add 1 to each element of an array:
var origArray = [1,2,3];
var newArray = origArray.map(function(item, index, array) {
return item + 1;
});
console.log(newArray); // [2,3,4]
Actual V8 source code:
If you really want to see how it is implemented inside of V8, here are code snippets and links to the relevant actual code files. As you can see, most of it is in C++ and to understand it, you have to understand how objects are structured in memory and what C++ methods they have internally in V8. This is very V8-specific, not general Javascript knowledge.
I've included links to the relevant source files too so if you want to see other context in those files, you can click on the links to see that.
In v8.h:
V8_DEPRECATED("Use maybe version", bool HasOwnProperty(Local<String> key));
V8_WARN_UNUSED_RESULT Maybe<bool> HasOwnProperty(Local<Context> context, Local<Name> key);
In api.cc:
Maybe<bool> v8::Object::HasOwnProperty(Local<Context> context,
Local<Name> key) {
PREPARE_FOR_EXECUTION_PRIMITIVE(context, "v8::Object::HasOwnProperty()",
bool);
auto self = Utils::OpenHandle(this);
auto key_val = Utils::OpenHandle(*key);
auto result = i::JSReceiver::HasOwnProperty(self, key_val);
has_pending_exception = result.IsNothing();
RETURN_ON_FAILED_EXECUTION_PRIMITIVE(bool);
return result;
}
bool v8::Object::HasOwnProperty(Local<String> key) {
auto context = ContextFromHeapObject(Utils::OpenHandle(this));
return HasOwnProperty(context, key).FromMaybe(false);
}
In v8natives.js:
// ES6 7.3.11
function ObjectHasOwnProperty(value) {
var name = TO_NAME(value);
var object = TO_OBJECT(this);
return %HasOwnProperty(object, name);
}
In objects-inl.h:
Maybe<bool> JSReceiver::HasOwnProperty(Handle<JSReceiver> object,
Handle<Name> name) {
if (object->IsJSObject()) { // Shortcut
LookupIterator it = LookupIterator::PropertyOrElement(
object->GetIsolate(), object, name, LookupIterator::HIDDEN);
return HasProperty(&it);
}
Maybe<PropertyAttributes> attributes =
JSReceiver::GetOwnPropertyAttributes(object, name);
MAYBE_RETURN(attributes, Nothing<bool>());
return Just(attributes.FromJust() != ABSENT);
}
In runtime-object.cc:
static Object* HasOwnPropertyImplementation(Isolate* isolate,
Handle<JSObject> object,
Handle<Name> key) {
Maybe<bool> maybe = JSReceiver::HasOwnProperty(object, key);
if (!maybe.IsJust()) return isolate->heap()->exception();
if (maybe.FromJust()) return isolate->heap()->true_value();
// Handle hidden prototypes. If there's a hidden prototype above this thing
// then we have to check it for properties, because they are supposed to
// look like they are on this object.
if (object->map()->has_hidden_prototype()) {
PrototypeIterator iter(isolate, object);
DCHECK(!iter.IsAtEnd());
// TODO(verwaest): The recursion is not necessary for keys that are array
// indices. Removing this.
// Casting to JSObject is fine because JSProxies are never used as
// hidden prototypes.
return HasOwnPropertyImplementation(
isolate, PrototypeIterator::GetCurrent<JSObject>(iter), key);
}
RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
return isolate->heap()->false_value();
}
RUNTIME_FUNCTION(Runtime_HasOwnProperty) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(Object, object, 0)
CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
uint32_t index;
const bool key_is_array_index = key->AsArrayIndex(&index);
// Only JS objects can have properties.
if (object->IsJSObject()) {
Handle<JSObject> js_obj = Handle<JSObject>::cast(object);
// Fast case: either the key is a real named property or it is not
// an array index and there are no interceptors or hidden
// prototypes.
// TODO(jkummerow): Make JSReceiver::HasOwnProperty fast enough to
// handle all cases directly (without this custom fast path).
Maybe<bool> maybe = Nothing<bool>();
if (key_is_array_index) {
LookupIterator it(js_obj->GetIsolate(), js_obj, index,
LookupIterator::HIDDEN);
maybe = JSReceiver::HasProperty(&it);
} else {
maybe = JSObject::HasRealNamedProperty(js_obj, key);
}
if (!maybe.IsJust()) return isolate->heap()->exception();
DCHECK(!isolate->has_pending_exception());
if (maybe.FromJust()) {
return isolate->heap()->true_value();
}
Map* map = js_obj->map();
if (!key_is_array_index && !map->has_named_interceptor() &&
!map->has_hidden_prototype()) {
return isolate->heap()->false_value();
}
// Slow case.
return HasOwnPropertyImplementation(isolate, Handle<JSObject>(js_obj),
Handle<Name>(key));
} else if (object->IsString() && key_is_array_index) {
// Well, there is one exception: Handle [] on strings.
Handle<String> string = Handle<String>::cast(object);
if (index < static_cast<uint32_t>(string->length())) {
return isolate->heap()->true_value();
}
} else if (object->IsJSProxy()) {
Maybe<bool> result =
JSReceiver::HasOwnProperty(Handle<JSProxy>::cast(object), key);
if (!result.IsJust()) return isolate->heap()->exception();
return isolate->heap()->ToBoolean(result.FromJust());
}
return isolate->heap()->false_value();
}
This is the node.js Github repository. If you know what to search for and have enough patience to wade through all the search hits, you can generally find anything you need. The unfortunate thing about searching on Github is I have not found any way to remove all the test sub-directories from the search so you end up with 95% of the search hits in the test code, not in the actual implementation code. But, with enough persistence, you can eventually find what you need.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Accessing nested JavaScript objects with string key
I have the function
function _get(name) {
return plugin._optionsObj[name] !== undefined ?
plugin._optionsObj[name] : plugin._defaults[name];
}
I would like to be able to have objects inside of my _defaults object, but then I don't know how to retrieve them but using just one set of square brackets.
i.e.
plugin._defaults = {
val1: 1,
val2: 2,
obj1: {
someVal: 3
}
}
Is it possible to access 'someVal' from the function I have above? I tried passing 'obj1.someVal' for the argument and it didn't work. Ideas?
Edit: I have found a solution and I posted it below as an answer. I've written a very nice little function to do go through the nested values with a string and I didn't have to change my function much to implement it. I hope this helps anyone in a similar situation.
I suspect that you won't always have a one-level nested object to access, so the cleaner way to do this is to use a function that traverses an object based on a string path. Here's one that is coded as a mixin for Underscore. You can then just use it like so:
_.deep(plugin._defaults, 'obj1.someVal');
This thread also has some non-Underscore alternatives.
Pass multiple arguments, and iterate over the arguments object.
function _get(/* name1, name2, namen */) {
var item = plugin._optionsObj,
defItem = plugin._defaults;
for (var i = 0; i < arguments.length; i++) {
item = item[arguments[i]];
defItem = defItem[arguments[i]];
if (item == null || defItem == null)
break;
}
return item == null ? defItem : item;
}
var opt = _get("obj1", "someVal")
I found a solution for this problem, at least one that will accommodate myself, and I'd like to share it in case it can help someone else with this problem. My biggest difficulty is that I did not know the depth of the nested value so I wanted to find a solution that would work for deeply nested objects and without requiring to redesign anything.
/* Retrieve the nested object value by using a string.
The string should be formatted by separating the properties with a period.
#param obj object to pass to the function
propertyStr string containing properties separated by periods
#return nested object value. Note: may also return an object */
function _nestedObjVal(obj, propertyStr) {
var properties = propertyStr.split('.');
if (properties.length > 1) {
var otherProperties = propertyStr.slice(properties[0].length+1); //separate the other properties
return _nestedObjVal(obj[properties[0]], otherProperties); //continue until there are no more periods in the string
} else {
return obj[propertyStr];
}
}
function _get(name) {
if (name.indexOf('.') !== -1) {
//name contains nested object
var userDefined = _nestedObjVal(plugin._optionsObj, name);
return userDefined !== undefined ? userDefined : _nestedObjVal(plugin._defaults, name);
} else {
return plugin._optionsObj[name] !== undefined ?
plugin._optionsObj[name] : plugin._defaults[name];
}
}
To retrieve objects inside of your _defaults object you'll need to improve your _get function.
For example you may pass an array of strings (each string representing a propery name) to _get to allow access to deeply nested objects.
When using AJAX, I tend to pass objects from my server to Javascript in the form of JSON objects (aka Javascript). Certain functions within my Javascript rely on the specific type of object I am using. For instance, lets use a phone number for example. I have a constructor:
function PhoneNumber(number, type, isPrimary, contactId, id, className) {
this.number = number;
this.type = type;
this.isPrimary = isPrimary;
this.contactId = contactId;
this.id = id;
this.className = className;
}
Which I use when creating a phone number object in my Javascript. In some situations I don't create the object in JS, I get the object from the server so it comes in the form of a generic object with the exact same fields. So when my code relies on the specific type by using something such as this:
var objType = objArray[i].constructor.name;
var mappedObj;
switch(objType) {
case 'PhoneNumber':
currentArray = currentArray.phone;
//Convert response to javascript object.
mappedObj = mapPhone(jsonResponse[i]);
break;
case 'Email':
currentArray = currentArray.email;
mappedObj = mapEmail(jsonResponse[i]);
break;
case 'Address':
currentArray = currentArray.address;
mappedObj = mapAddress(jsonResponse[i]);
break;
case 'Website':
currentArray = currentArray.website;
mappedObj = mapWebsite(jsonResponse[i]);
}
In this situation, I check the name of the objects constructor and set certain variables based on that name. If the object I check the name on is a JSON from the server, it simply gives me a generic "Object" response and thus the code does not work. I get around this by using a mapping function for each object such as:
function mapPhone(phoneObj) {
var id = phoneObj.id;
var contactId = phoneObj.contactId;
var number = phoneObj.number;
var type = phoneObj.type;
var primary = phoneObj.isPrimary;
var className = phoneObj.className;
var phoneNumber = new PhoneNumber(number, type, primary, contactId, id, className);
return phoneNumber;
}
This works just fine, but to me seems a little redundant. Is this the best way to solve the JSON Object problem, or is there a better solution? I understand this is more of a "Am I doing this the best way possible" type of question, but I repeat this type of logic CONSTANTLY in my Javascript code and I figure I might as well get another opinion or two on whether or not its the proper way to do this before I have to spend hour upon hour fixing it in the future.
EDIT: I ended up accepting a jQuery solution because I happen to use jQuery in my project. There are however multiple solutions that also worked for me before I found the jQuery option. They just weren't quite as clean and efficient.
The following requires you to have the same properties in your object and your JSON object.
var phoneNumber = $.extend(new PhoneNumber(), yourJSONObject);
This basically creates a new PhoneNumber object and then copies all properties from your JSON object onto it. The $.extend() method is from jQuery, but you could also use as similar method from e.g. Underscore.js or one of the other js libraries/frameworks.
This similar question has a lot of interesting answers:
Parse JSON String into a Particular Object Prototype in JavaScript
Based off the poster's own answer, I think this would be an effective solution for you:
function recastJSON(jsonObject) {
// return generic object if objectType is not specified
if (!jsonObject.objectType)
return jsonObject;
// otherwise create a new object of type specified
var obj = eval('new '+jsonObject.objectType+'()');
for(var i in jsonObject)
obj[i] = jsonObject[i];
return obj;
}
You will need to add objectType to the JSON objects you are receiving to define the javascript class you want to instantiate. Then when you call this function, it will cast the object to that type and copy the data over (including the variable 'objectType').
Using your phone number example, your code would look like this:
// generic object from JSON
var genericObject = {objectType:'PhoneNumber', number:'555-555-5555', type:'home', primary:true, contactId:123, id:1234, className:'stdPhone'};
var phoneObject = recastJSON(genericObject);
AFAIK, in everything that is not IE, you can do this:
// define a class
var Foo = function(name) {
this.name = name;
}
// make a method
Foo.prototype.shout = function() {
return "I am " + this.name;
}
// make a simple object from JSON:
var x = JSON.parse('{ "name": "Jason" }');
// force its class to be Foo
x.__proto__ = Foo.prototype;
// the method works
x.shout();
Unfortunately, IE does not support the __proto__ accessor, so what you would need to do is first create an empty instance of your object, then just copy everything over:
// make a simple object from JSON:
var x = JSON.parse('{ "name": "Jason" }');
// make an empty Foo
var y = Object.create(Foo.prototype);
// copy stuff over
for (a in x) {
y[a] = x[a];
}
y.shout();
Both of these approaches are quite a bit more generic than your mapWhatever functions, keeping it DRY.
If not supporting older browsers is ok, You can use Object.create to do the mapping for you. (dropping the shim—at least the shim at MDN—in will not fix older browsers, since that shim does not accept the second parameter.)
DEMO
function makeThisExtend(obj, CtorFunc) {
for (var k in obj)
if ({}.hasOwnProperty.call(obj, k))
obj[k] = { value: obj[k] };
return Object.create(CtorFunc.prototype, obj);
}
var objFromServer = { Number: "123", id: 5 };
objFromServer = makeThisExtend(objFromServer, PhoneNumber);
alert(objFromServer.Number + " " + objFromServer.id); //123 5
alert(objFromServer.constructor); //function PhoneNumber ...