This question already has answers here:
Is there a way to provide named parameters in a function call in JavaScript?
(12 answers)
Closed 8 years ago.
If I have a function with parameters (or argument) like this:
check('red', 'blue', 'arial')
What i would like to know is can you have text like this:
check(background:'red', color:'blue', font:'arial')
In the function I have a if statement so if the parameter or argument has background: before it, it changes the background to the parameter after the background:
function check(one, two, three){
if (one==background:one){
document.body.style.background= one ;
}
}
I know this doesn't work, how would you do this or something like it?
Can I use a if statement but code it to detect if a parameter has 'background:' before it? Is this possible or is there a better way of doing it?
I would like to use pure JavaScript if that is possible.
JavaScript does not support labeled function arguments (a la C# and other languages). However, it would be easy enough to pass in a configuration object instead:
function check(config) {
// config.background
// config.color
// config.font
}
check({ background: 'red', color: 'blue', font: 'arial' });
If you need or want the function to also support being called with regular parameters, you can always detect argument types:
function check(background, color, font) {
if(typeof background === 'object') {
color = background.color;
font = background.font;
background = background.background;
}
// background, color, and font are what you expect
}
// you can call it either way:
check('red', 'blue', 'arial');
check({ background: 'red', color: 'blue', font: 'arial' });
And, finally, if you don't want to (or somehow can't) modify the original function, you can wrap it:
var originalCheck = check;
check = function(config) {
originalCheck(config.background, config.color, config.font);
}
Related
question
How to set an object property value to its own variable name (during initialization if possible)?
eg
For example, to create a Enum (inside class AA) in Javascript:
class AA {
static Color = {
Red: 'Red',
Green: 'Green',
Blue: 'Blue',
}
}
I have to repeat the String name everytime.
Is there a simpler way to do this, something like eg:
class AA {
static Color = {
Red: this.currentProperty.name,
Green: this.currentProperty.name,
Blue: this.currentProperty.name,
}
}
requirements (not mandatory) & comments
Please make this As Simple As Possible (dont be complicated/cumbersome).
(The hardest requirement. It would be best in the form shown above (during initialization).
I may be a bit picky on this... (I know this is very subjective, and such thing may not even exist)
though, any other thoughts are still welcome)
The variable value & variable name can be refactored at the same time -- without the need to change them separately.
It doesnt have to be an Enum (-- this topic is not limited to Enum only, a normal object will do)
Try to use Es6+
Try to let Jsdoc able to recognize this as an Enum (maybe the use of #emun (?<)), (mainly for autocompletion / Type hint on Vscode)
Try to let Debugger able to recognize this as an Enum & able to view the value as a meaningful string
Im aware of there are some Enum lib in github eg, not sure they are good enough / fit my style.
Im aware of the use of Symbol() on Enum
Im aware of need to make Enum immutable (private + getter / Object.freeze)
I dont think Object.keys() can help. (too cumbersome?)
class AA {
static Color = Object.fromEntries(['Red','Green','Blue'].map(i=>[i,i]))
}
console.log(AA.Color)
or, with a helper method:
function makeEnum(...props) { return Object.fromEntries(props.map(i=>[i,i])) }
class AA {
static Color = makeEnum('Red','Green','Blue')
}
console.log(AA.Color)
this might help with autocompletion:
function makeEnum(obj) { return Object.fromEntries(Object.keys(obj).map(i=>[i,i])) }
class AA {
static Color = makeEnum({Red:'', Green:'', Blue:''})
}
console.log(AA.Color)
or using a proxy:
function makeEnum() {
let o = {}, p = new Proxy(o, {get:(_,i)=>(i==='enum'?o:(o[i]=i,p))})
return p
}
class AA {
static Color = makeEnum().Red.Green.Blue.enum
}
console.log(AA.Color)
including Object.freeze() to prevent reassignment:
function makeEnum() {
let o = {}, p = new Proxy(o, {get:(_,i)=>
(i==='enum'?(Object.freeze(o),o):(o[i]=i,p))})
return p
}
class AA {
static Color = makeEnum().Red.Green.Blue.enum
}
console.log(AA.Color)
AA.Color.Red = 'Yellow'
console.log(AA.Color)
another proxy variant: the new keyword is used to trigger freezing of the object:
function Enum() {
let o={}, p = new Proxy(function() {}, {
construct: () => (Object.freeze(o),o),
get:(_,i)=>(o[i]=i,p)
});
return p;
}
class AA {
static Color = new (Enum().Red.Green.Blue)
}
console.log(AA.Color)
console.log(AA.Color.Red)
AA.Color.Red = 'Yellow' // frozen object can't be changed
console.log(AA.Color.Red)
AA.Color.Orange = 'Orange' // frozen object can't accept new properties
console.log(AA.Color)
I am creating a javascript class to handle SVG tags in HTML. (I know that there are plenty of classes that does this already but I did not succeed with transformations via svg.js. Also, I have made all the required functions to work and I just want to implement them as a class for syntactical ease.)
However, not being that familiar with javascript, I have trouble with a variable that is set to Undefined in my constructor:
class SLD {
constructor(container,x=1000, y=1000) {
this.ctn = document.getElementById(container);
this.svgobj = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
// Defining object attributes
var obj = {
'width': "1000",
'height': "1000",
'xmlns':"http://www.w3.org/2000/svg",
'version':"1.1",
'xmlns:xlink':"http://www.w3.org/1999/xlink"
};
// Setting attribute via for loop
for(prop in obj) {
this.svgobj.setAttribute(prop, obj[prop])
}
}
While trying to run it, I am returned the following error code:
How do I define the variable properly? I am using Chrome (version 83.0.4103.116) and the browser supports classes as far as I am noticed.
Let me know if I should provide any other relevant information.
I assume prop hasn't been declared yet so you'll need to use var.
for(var prop in obj) {
this.svgobj.setAttribute(prop, obj[prop])
}
You could try this:
for (const prop in obj) {
this.svgobj.setAttribute(prop, obj[prop]);
}
Variable declaration was your problem.
Your code could be optimized by replacing the for loop with:
Object.entries({
'width': "20",
'height': "20",
'xmlns':"http://www.w3.org/2000/svg",
'version':"1.1",
'xmlns:xlink':"http://www.w3.org/1999/xlink"
}).forEach(([prop,value])=>svgobj.setAttribute(prop, value));
Background
We have much of our data formatted like
var X = {value:'some val',error:'maybe an error',valid:true}
as a result we find ourselves calling X.value ALL the time.
We don't use the .error or .valid nearly as much, but we do use it.
What I want
To quit calling .value everywhere, but to still have access to meta data on a per data point level.
The Question
Is there one of
A) A way to put meta data on a primitive? attaching .error to an int for example? Is it possible for bools or strings?
B) A way to make a class that can be treated as a primitive, providing a specific data member when I do? IE X.value = 5, X+3 returns 8.
C) A better design for our data? Did we just lay this out wrong somehow?
You can set the method toString() to your object and return value.
var X = {
value: 1,
error:'maybe an error',
valid:true,
toString: function() {
return this.value;
}
}
X.value = 5;
console.log(X+3);
You can represent you data as a function object that also has properties:
var X = () => 1;
X.value = 1;
X.error = 'maybe an error';
X.valid = true,
console.log(X()); // 1
console.log(X.valid); // true
For better design you can encapsulate the creation of the data object in another function.
I extended default less functions to support some basic lists. I added a function 'nth' given as following:
"nth": function(obj, index){
var list = obj.value.split(",");
var n = index.value;
obj.value = list[n-1].trim();
return new tree.Anonymous(obj);
}
Then I added another function 'convertstrtovar' as following:
convertstrtovar: function(obj){
var str = obj.value.toString();
str = str.replace(/(#)/gi, '');
str = '~"#{' + str + '}"';
obj.value = str;
return new tree.Anonymous(obj);
}
This receives String like '#white' and converts it to ~"#{white}". Sample code for less mixin is given below.
#button-text-colors: "#white, #dark, #red"; //parsed as a comma separated list.
#white: white;
#dark: black;
#red: red;
.something(#color){
color: #color;
}
.some{
#t: convertstrtovar(nth(#button-text-colors, 1));
.something(#t);
}
This gives me output as following:
.some {
color: ~"#{white}";
}
Why is ~"#{white}" being printed out as string and not evaluated as variable white when usually ~"#{white}" in less get the value stored in #white?
Why is ~"#{white}" being printed out as string and not evaluated as variable white when usually ~"#{white}"
Because LESS evaluates those things when it parses the input (but your function creates a new string object after that).
Actually you can achieve what you want just with default LESS language constructs (w/o any need for custom function hacks):
#button-text-colors: 'white', 'dark', 'red';
#white: white;
#dark: black;
#red: red;
.something(#color){
color: #color;
}
.some{
#t: extract(#button-text-colors, 1);
.something(##t);
}
No, seriously, I would suggest you to consider to learn more about existing LESS features before trying to extend it with you own custom functions... (Though I must admit the outdated LESS documentation is a significant problem - well, at least take a look at https://github.com/SomMeri/less4j/wiki/_pages - this is the most detailed LESS documentation for the moment).
I am looking for a way to retrieve the style from an element that has a style set upon it by the style tag.
<style>
#box {width: 100px;}
</style>
In the body
<div id="box"></div>
I'm looking for straight javascript without the use of libraries.
I tried the following, but keep receiving blanks:
alert (document.getElementById("box").style.width);
alert (document.getElementById("box").style.getPropertyValue("width"));
I noticed that I'm only able to use the above if I have set the style using javascript, but unable to with the style tags.
The element.style property lets you know only the CSS properties that were defined as inline in that element (programmatically, or defined in the style attribute of the element), you should get the computed style.
Is not so easy to do it in a cross-browser way, IE has its own way, through the element.currentStyle property, and the DOM Level 2 standard way, implemented by other browsers is through the document.defaultView.getComputedStyle method.
The two ways have differences, for example, the IE element.currentStyle property expect that you access the CCS property names composed of two or more words in camelCase (e.g. maxHeight, fontSize, backgroundColor, etc), the standard way expects the properties with the words separated with dashes (e.g. max-height, font-size, background-color, etc).
Also, the IE element.currentStyle will return all the sizes in the unit that they were specified, (e.g. 12pt, 50%, 5em), the standard way will compute the actual size in pixels always.
I made some time ago a cross-browser function that allows you to get the computed styles in a cross-browser way:
function getStyle(el, styleProp) {
var value, defaultView = (el.ownerDocument || document).defaultView;
// W3C standard way:
if (defaultView && defaultView.getComputedStyle) {
// sanitize property name to css notation
// (hypen separated words eg. font-Size)
styleProp = styleProp.replace(/([A-Z])/g, "-$1").toLowerCase();
return defaultView.getComputedStyle(el, null).getPropertyValue(styleProp);
} else if (el.currentStyle) { // IE
// sanitize property name to camelCase
styleProp = styleProp.replace(/\-(\w)/g, function(str, letter) {
return letter.toUpperCase();
});
value = el.currentStyle[styleProp];
// convert other units to pixels on IE
if (/^\d+(em|pt|%|ex)?$/i.test(value)) {
return (function(value) {
var oldLeft = el.style.left, oldRsLeft = el.runtimeStyle.left;
el.runtimeStyle.left = el.currentStyle.left;
el.style.left = value || 0;
value = el.style.pixelLeft + "px";
el.style.left = oldLeft;
el.runtimeStyle.left = oldRsLeft;
return value;
})(value);
}
return value;
}
}
The above function is not perfect for some cases, for example for colors, the standard method will return colors in the rgb(...) notation, on IE they will return them as they were defined.
I'm currently working on an article in the subject, you can follow the changes I make to this function here.
I believe you are now able to use Window.getComputedStyle()
Documentation MDN
var style = window.getComputedStyle(element[, pseudoElt]);
Example to get width of an element:
window.getComputedStyle(document.querySelector('#mainbar')).width
In jQuery, you can do alert($("#theid").css("width")).
-- if you haven't taken a look at jQuery, I highly recommend it; it makes many simple javascript tasks effortless.
Update
for the record, this post is 5 years old. The web has developed, moved on, etc. There are ways to do this with Plain Old Javascript, which is better.
Use getComputedStyle function, Computed style contains all the CSS properties set to an element. Even if do not set a property to an element. You will still find that property in the computed styles.
Example:
<style>
#Body_element {
color: green;
}
</style>
<body id="Body_element">
<script>
alert(getComputedStyle(Body_element).color)
</script>
</body>
This is a helper function if you want to get multiple style rules from the same element.
You pass it the element and the styles you want as arguments, and it will return their values
const convertRestArgsIntoStylesArr = ([...args]) => {
return args.slice(1);
}
const getStyles = function () {
const args = [...arguments];
const [element] = args;
let stylesProps = [...args][1] instanceof Array ? args[1] : convertRestArgsIntoStylesArr(args);
const styles = window.getComputedStyle(element);
const stylesObj = stylesProps.reduce((acc, v) => {
acc[v] = styles.getPropertyValue(v);
return acc;
}, {});
return stylesObj;
};
Now, you can use this function like this:
const styles = getStyles(document.body, "height", "width");
OR
const styles = getStyles(document.body, ["height", "width"]);