What does $.support.placeholder mean in jQuery? - javascript

I don't understand this condition: $.support.placeholder
Can anyone explain to me what this is for?
if ($.support.placeholder) {
alert("Testing");
} else {
return;
}

It's checking to see if the placeholder property on the $.support object is truthy¹ and, if so, it does the alert; if not, it does a return, exiting the function this code is in.
jQuery's support object (long deprecated, it shouldn't be used anymore) tells you what the current browser supports. From the link:
A collection of properties that represent the presence of different browser features or bugs. Intended for jQuery's internal use; specific properties may be removed when they are no longer needed internally to improve page startup performance. For your own project's feature-detection needs, we strongly recommend the use of an external library such as Modernizr instead of dependency on properties in jQuery.support.
(my emphasis)
In this case, the check is seeing if the browser supports the placeholder attribute on input elements. But see above, the check is unreliable. If jQuery no longer needs to know this information internally, the property may be removed, and that code would be tricked into thinking the browser didn't support placeholder (which nearly all do) because getting the value of a property that doesn't exist results in undefined, which is falsy.
In fact, the current version of jQuery as of this writing (v3.3.1) doesn't have placeholder:
console.log("typeof $.support.placeholder:", typeof $.support.placeholder); // "typeof $.support.placeholder: undefined"
var input = document.createElement("input");
input.type = "text";
var supportsPlaceholder = "placeholder" in input;
console.log("supportsPlaceholder: ", supportsPlaceholder); // "supportsPlaceholder: true" (in nearly all browsers)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
The code in the question would incorrectly report that your browser doesn't have placeholder support even when it does.
¹ a truthy value is a value that coerces to true when used as a boolean, such as in an if. A falsy value is one that coerces to false. The falsy values are null, undefined, 0, NaN, "", and of course, false; all other values are truthy.

Related

How can a read only property(element.classList) can be modified or assigned to some other value in javascript?

window.addEventListener('keydown',function(e) {
const key= document.querySelector(`div[data-key='${e.keyCode}']`);
console.log(key.className);
console.log(key.classList);
key.classList=['ajay','dish'];
}
<div data-key="65" class="key ajay">
<kbd>A</kbd>
</div>
Above is a screenshot of chrome devtools with values modified.
I read on MDN that element.classList is read only property but can be modified by add() etc.
I assigned it to some other array and that is working too.
In other cases, whenever I tried to modify/assign read only property, it always gave typeError.
Very good question.
I did not originally know the exact answer to your question, but I'm not surprised as much by the behaviour. The spec defines the minimum that all compliant useragents (browsers) must implement. It also defines all the features that developers can expect and rely on when targeting compliant useragents (browsers). It's up to the browsers to add additional non-standard features.
This means that all browsers have to implement a get property called classList. Developers should only expect a get property to be available in browsers. Browsers might think it's convenient for developers to have a set function implemented too. It's fairly common for browsers to do this kind of thing. Sometimes this kind of features gets added to a newer version of the standard, sometimes it never makes it because the standard committee disagrees with the purity of the feature.
Sometimes non-standard features get deprecated and even removed, which although takes years - is a good reason for developers to not rely on non standard features when other standard features can achieve the same goal (for example, the property className can be used to override the classList).
But how is it done technically after all?
Chrome implements this in a very clever way (might be originally WebKit). It applies an attribute PutForwards to the definition of classList.
This allows the property to be defined as readonly, but when assigned a value, one of the properties of the object gets assigned instead, not the entire object. In this case, the child property name is value.
So, the code document.body.classList = '123';
is the same as document.body.classList.value = '123';
You can confirm the object was not replaced by running the following in Chrome console
const body = document.body;
const oldClassList = body.classList;
const oldValue = body.classList.value;
body.classList = "new-class";
const newClassList = body.classList;
const newValue = body.classList.value;
console.log(
"classList changed:", oldClassList !== newClassList, // false
"value changed:", oldValue !== newValue // true
);
The definition of classList in Chromium source code
[Affects=Nothing, SameObject, PerWorldBindings, PutForwards=value] readonly attribute DOMTokenList classList;
can be found at:
https://github.com/chromium/chromium/blob/4141778eb03a31a20d9e109f74faf2f756b4a8c4/third_party/blink/renderer/core/dom/element.idl#L37
Note how this is different from the definition in the spec
[SameObject] readonly attribute DOMTokenList classList;`
which can be found at https://www.w3.org/TR/dom/#element
And the test in the source code that explains the relation between the attribute and the ability to override the readonly property in its comment
// Even though classList is readonly, PutForwards=value means that its value is forwarded.
can be found at:
https://github.com/chromium/chromium/blob/f18e79d901f56154f80eea1e2218544285e62623/third_party/WebKit/LayoutTests/fast/dom/HTMLElement/resources/class-list.js#L13

Primitives and Object Wrapper Equivalence in JavaScript

EDIT: Based on everyone's feedback, the original version of this question is more design-related, not standards-related. Making more SO-friendly.
Original:
Should a JS primitive be considered "equivalent" to an object-wrapped version of that primitive according to the ECMA standards?
Revised Question
Is there a universal agreement on how to compare primitive-wrapped objects in current JavaScript?
var n = new Number(1),
p = 1;
n === p; // false
typeof n; // "object"
typeof p; // "number"
+n === p; // true, but you need coercion.
EDIT:
As #Pointy commented, ECMA spec (262, S15.1.2.4) describes a Number.isNaN() method that behaves as follows:
Number.isNaN(NaN); // true
Number.isNaN(new Number(NaN)); // false
Number.isNaN(+(new Number(NaN))); // true, but you need coercion.
Apparently, the justification for this behavior is that isNaN will return true IF the argument coerces to NaN. new Number(NaN) does not directly coerce based on how the native isNaN operates.
It seems that the performance hit and trickiness in type conversion, etc, of directly using native Object Wrappers as opposed to primitives outweighs the semantic benefits for now.
See this JSPerf.
The short answer to your question is no, there is no consensus on how to compare values in JS because the question is too situational; it depends heavily on your particular circumstances.
But, to give some advice/provide a longer answer .... object versions of primitives are evil (in the "they will cause you lots of bugs sense", not in a moral sense), and should be avoided if possible. Therefore, unless you have a compelling reason to handle both, I'd suggest that you do not account for object-wrapped primitives, and simply stick to un-wrapped primitives in your code.
Plus, if you don't account for wrapped primitives it should eliminate any need for you to even have an equals method in the first place.
* Edit *
Just saw your latest comment, and if you need to compare arrays then the built-in == and === won't cut it. Even so, I'd recommend making an arrayEquals method rather than just an equals method, as you'll avoid lots of drama by keeping your function as focused as possible and using the built-in JS comparators as much as possible.
And if you do wrap that in some sort of general function, for convenience:
function equals(left, right) {
if (left.slice && right.slice) { // lame array check
return arrayEquals(left, right);
}
return left == right;
}
I'd still recommend against handling primitive-wrapped objects, unless by "handle" you make your function throw an error if it's passed a primitive-wrapped object. Again, because these objects will only cause you trouble, you should strive to avoid them as much as possible, and not leave yourself openings to introduce bad code.

typeof returning "unknown" in IE

I have a window, where before being closed I refresh the underlying page.
if(opener && typeof(opener.Refresh) != 'undefined')
{
opener.Refresh();
}
If I moved away from the original opening page, this code would throw a "Permission Denied" error.
Debugging the code revealed that typeof(opener.Refresh) was equal to "unknown" instead of the expected "undefined".
As far as I'm aware "unknown" is not one of the return values for typeof, so how and why would this value be returned?
Further Information
I avoided the error by changing the check to:
if(opener && typeof(opener.Refresh) == 'function')
However examples like this (detecting-an-undefined-object-property-in-javascript) do not seem to factor "unknown" into the equation.
According to a duplicate question at Bytes, the typeof value unknown is added to JScript version 8, along with date.
A comment to a blog by Robert Nyman can also be explanatory:
Internet Explorer displays “unknown” when the object in question is on
the other side of a COM+ bridge. You may not know this or realize
this, but MS’s XMLHTTP object is part of a different COM+ object that
implements IUnknown; when you call methods on it, you’re doing so over
a COM bridge and not calling native JavaScript.
Basically that’s MS’s answer if you try to test or access something
that’s not a true part of the JScript engine.
Try in operator. I had the same problem (with applet) and I solved it using in:
if("Refresh" in opener) {
opener.Refresh();
}
The ECMAScript specification states that for host objects the return value of the typeof operator is:
Implementation-defined except may not be "undefined", "boolean",
"number", or "string".
I believe the unknown value is only ever returned in Internet Explorer. Interestingly, MSDN does not mention it:
There are six possible values that typeof returns: "number," "string,"
"boolean," "object," "function," and "undefined."

Check if something works

I'm trying to test what is available on a specific browser (JavaScript-wise).
If I just typed this for example:
function checksetAttribute(){
if(document.getElementById("blar").setAttribute("name","blarDiv")){
alert("Your browser supports it.");
}
else{
alert("Your browser does not support it.");
}
}
Would this return a true answer as to whether or not the property(ies) work?
If you want to test whether a certain property works, not whether setAttribute works, then this is the wrong approach, as setAttribute always returns undefined (== false). Instead, test whether the element has the attribute name as a key - and use a new element instead of one pulled from the DOM, because elements in the DOM could have been modified.
function attributeWorks(attr, within) {
return document.createElement(within || 'div').hasOwnProperty(attr);
}
I added the within parameter because some properties exist only on certain types of elements: for example, if you always test against a <div>, then the function will return false for href.
If you want to test whether the setAttribute function works this is still the wrong approach, because, if setAttribute is not implemented, trying to execute it will throw an error instead of returning false. We can use the same method as above, with the simplification that we already know the parameters:
function setAttributeWorks() {
return document.createElement('div').hasOwnProperty('setAttribute');
}
No. Assuming the browser supports document.getElementById and setAttribute, it will just set the name attribute. As that method returns void (which is falsy), it will always alert "Your browser does not support it." - unless an Exception is thrown.
It neither will check whether the browser supports name attributes.
I am guessing that the code you have there would fail if "setAttribute" was not supported.
var a = document.createElement("div");
if(a.setAttribute){
alert("VERY SUPPORTED");
}else{
alert("Not supported");
}
This would check to see if the setAttribute method is available on dom elements.

What is the best way to tell users of my library functions that passed variables are not of the correct type

I'm currently in the creation of a javascript function library. Mainly for my own use, but you can never be sure if someone else ends up using it in their projects, I'm atleast creating it as if that could happen.
Most methods only work if the variables that are passed are of the correct datatype. Now my question is: What is the best way to alert users that the variable is not of the correct type? Should one throw an error like this?
function foo(thisShouldBeAString){ //just pretend that this is a method and not a global function
if(typeof(thisShouldBeAString) === 'string') {
throw('foo(var), var should be of type string');
}
#yadayada
}
I know that javascript does internal type conversion, but this can create very weird results (ie '234' + 5 = '2345' but '234' * 1 = 234) and this could make my methods do very weird things.
EDIT
To make things extra clear: I do not wish to do type conversion, the variables passed should be of the correct type. What is the best way to tell the user of my library that the passed variables are not of the correct type?
The problem with type checking is that its actually quite hard to do. For example:-
var s = new String("Hello World!");
alert(typeof s);
What gets alerted? Ans: "object". Its true its a daft way to initialise a string but I see it quite often none-the-less. I prefer to attempt conversions where necessary or just do nothing.
Having said that in a Javascript environment in which I have total control (which is not true if you are simply providing a library) I use this set of prototype tweaks:-
String.prototype.isString = true;
Number.prototype.isNumber = true;
Boolean.prototype.isBoolean = true;
Date.prototype.isDate = true;
Array.prototype.isArray = true;
Hence testing for the common types can be as simple as:-
if (x.isString)
although you still need to watch out for null/undefined:-
if (x != null && x.isString)
In addition to avoiding the new String("thing") gotcha, this approach particularly comes into its own on Dates and Arrays.
Some small remarks on type checking - it's actually not that complicated:
Use typeof to check for primitives and instanceof to check for specific object types.
Example: Check for strings with
typeof x === 'string'
or
typeof x === 'string' || x instanceof String
if you want to include string objects.
To check for arrays, just use
x instanceof Array
This should work reasonably well (there are a few known exceptions - eg Firefox 3.0.5 has a bug where window instanceof Object === false although window.__proto__ instanceof Object === true).
edit: There are some further problems with detection of function objects:
In principle, you could both use typeof func === 'function' and func instanceof Function.
The catch is that in an unnamed browser from a big corporation these checks return the wrong results for some predefined functions (their type is given as 'object'). I know of no workaround for this - the checks only work reliably for user-defined functions...
edit2: There are also problems with objects passed from other windows/frames, as they will inherit from different global objects - ie instanceof will fail. Workarounds for built-in objects exists: For example, you can check for arrays via Object.prototype.toString.call(x) === '[object Array]'.
Libraries like jQuery do not inform the user of the error.
If a function is expecting a number, and a user passes a string, the function just returns without doing anything.
That way, you will avoid JavaScript errors popping up on a live website.
PS. Just make sure to always type check your inputted parameters, to avoid JavaScript errors being thrown.
How about throw:
https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Statements/throw
Also type of does not distinguish between Array, Null, Object very well. Look at the funciton here: http://javascript.crockford.com/remedial.html, plus there are a few other ways to do it.
Personally I would not do the type checking since it is a step that will just add more processing time to the code. If you care about performance, you would want to chop off as many milliseconds of processing time as possible. Good Documentation will cure the need for the check.
What's about just to silently convert string to numeric datatype on function startup?
You always can determine the datatype of 'string'. Can't you?
You could check for some value like "debug=1" set. If there is - you could output errors like alerts. So in development mode user will see them, but on real site he will turn it off. Same way browser will not show you error message - you need to look at JS console.
Also there is FireBug. You could detect that and put FB debug Messages also.

Categories

Resources