I am creating a scriptable application using the native windows API and the chakrart JavaScript engine.
I have interfaces like the following in my IDL:
[oleautomation, dual, nonextensible,
uuid(...)]
interface IMyInterface : IDispatch
{
[id(MYDISPID_EVENT), propget] HRESULT Event(BSTR strEventName, [out, retval] IDispatch ** ppHandler);
[id(MYDISPID_EVENT), propput] HRESULT Event(BSTR strEventName, IDispatch * pHandler);
};
I have been able to add the native objects to the chakrart engine without trouble (by using JsVariantToValue and then setting a property on the global object of the current context). However when I attempt to set an event handler I get the exception message 'Object doesn't support this property or method'.
I have tried the following syntax variations:
object.Event["foo"] = handler;
object.Event("foo", handler);
object.put_Event("foo", handler);
object.Event("foo") = handler;
That last is close to how this would be done using vbscript:
object.Event("foo") = GetRef("handler)
If I use method syntax in the IDL like the following it works, I would simply prefer to use property assignment if possible.
[id(MYDISPID_GETEVENT)] HRESULT GetEvent(BSTR strEventName, [out, retval] IDispatch ** ppHandler);
[id(MYDISPID_SETEVENT)] HRESULT SetEvent(BSTR strEventName, IDispatch * pHandler);
And also note that simple property assignments do work, it is only when I try indexed properties that it breaks. I do understand that JavaScript does something very different with object[prop] syntax, at least for native JavaScript objects. Is this perhaps simply an incompatibility in the chakrart interop layer?
I have confirmed a way to perform this with the desired syntax (App.Event['foo'] = someHandler;). As mentioned I already knew JavaScript treats name['foo'] as a member lookup on name
Have the App object implement a propget for Event that returns an object with a custom (non-dual interface) IDispatch implementation. That object keeps a map of names to DISPIDs and whenever an unknown name is requested via GetIDsOfNames a previously unassigned DISPID is returned.
Note that in order to comply with the rules for IDispatch the object needs to keep track of names even if a null handler is later assigned to a given name, so that the same DISPID will always be returned for a particular name.
Related
I am learning javascript.
var label = document.getElementById('lblMsg');
If I inspect the element with F12, its described as an HTMLSpanElement. I cannot cast the element to its type, like:
var label = (HTMLSpanElement) document.getElementById('lblMsg');
So whats the use for HTMLSpanElement ? Does it have any properties différent than the other HTMLElements ?
Since you are a beginner, I'm going to point out a few basic facts that may help you make some sense of what you are observing.
JavaScript is weakly typed
Objects in JavaScript do have types, but variables are not typed, i.e. any variable can take any object of any type. Type casting is not necessary, nor is it possible (and in fact the line (HTMLSpanElement) document.getElementById('lblMsg') is a syntax error).
HTML elements types
HTMLSpanElement is a type. Well, not really. It's a DOM interface, which is treated as a native object type by all modern browsers for convenience. Most HTML elements have the type of their main interface.
The point of interfaces is to expose a set of methods, properties or events available to all implementations. You already have the MDN link for HTMLSpanElement: https://developer.mozilla.org/en-US/docs/Web/API/HTMLSpanElement.
Testing for a type
To test if an object is an instance of a particular type, we can use obj instanceof Type. In this case:
if (document.getElementById('lblMsg') instanceof HTMLSpanElement)
{
...
}
Type inheritance is always honored.
document.getElementById('lblMsg') instanceof Object // true
Getting an object's type
To get the type of an HTML element, we use element.constructor, as in
document.getElementById('lblMsg').constructor
If you enter this in the browser console, you will see something like
`function HTMLSpanElement() { [native code] }`
Don't be surprised. Object types are functions in JavaScript. If we were just interested in the name of this object's type, we could use
document.getElementById('lblMsg').constructor.name
Which yields the string "HTMLSpanElement"
This method of determining an object's type is not 100% foolproof, but it works for all builtin objects.
I have an odd situation in my Javascript code which I cannot explain. So far it has been observed only on Safari/Mac.
I have a line like this:
dict[id].sliceHovered = true;
And sometimes it throws an error:
Attempted to assign to readonly property.
Also:
dict is a bare blank object which I create myself with dict={}.
id is supplied by outside data, so it can be anything (I don't yet know which particular value causes this).
sliceHovered is obviously not a name of something that Javascript has built
in.
The objects in the dict are of my own type. They have a sliceHovered member, but it's not a Javascript defined property (as in Object.defineProperty()), just a regular property (the constructor executes this.sliceHovered=false).
"use strict" is on.
Object.freeze(), Object.seal(), Object.preventExtensions() and const are not used anywhere in the entire codebase.
Thus it's extremely puzzling as to how such an error could be thrown here. If I had an indexing error and dict[id] would be undefined or null, the error would be different. My only idea is that since the dict is created as dict={} then it inherits from Object and maybe id maps to some inherited property. But that means that the object returned from dict[id] would have to be read-only itself, because sliceHovered is definitely not a name of an existing Javascript property.
However I cannot think of any Javascript objects that would be intrinsically read-only like that.
Any ideas what could be wrong here?
You can check this situation
My only idea is that since the dict is created as dict={} then it inherits from Object
with: var dict = Object.create(null);
Also try to use Object.getOwnPropertyDescriptor(dict, id) to make sure descriptors have right values.
I've noticed ## used in a few pages about new ES6 features, but I don't know what exactly it means (whether it's actually syntax or just some kind of documentation convention). And it's hard to google. Can someone explain it?
## describes what's called a well-known symbol. (Note that it isn't actually valid syntax in JS.) According to the ES6/ES20151 specification:
Well-known symbols are built-in Symbol values that are explicitly referenced by algorithms of this specification. They are typically used as the keys of properties whose values serve as extension points of a specification algorithm. Unless otherwise specified, well-known symbols values are shared by all Code Realms (8.2).
Code Realms refer to different instances of a JavaScript environment. For example, the Code Realm of the root document would be different to that of JavaScript running in an <iframe>.
An example of where it matter what code realm an object comes from is when trying to use instanceof to determine whether an object is an array (hint: it won't work if it's from another frame). To avoid these kinds of issues from popping up with symbols, they are shared so that references to (say) ##toString will work no matter where the object came from.
Some of these are exposed directly through the Symbol constructor, for example, ##toPrimitive is exposed as Symbol.toPrimitive. That can be used to override the value produced when attempting to convert an object to a primitive value, for example:
let a = { [Symbol.toPrimitive]: () => 1 };
console.log(+a); // 1
console.log(a.valueOf()); // (the same object)
console.log(a.toString()); // "[object Object]"
In general, symbols are used to provide unique properties on an object which cannot collide with a random property name, for example:
let a = Symbol();
let foo = { [a]: 1 };
foo[a]; // 1
There is no way to access the value except by getting the symbol from somewhere (though you can get all symbols for an object by calling Object.getOwnPropertySymbols, so they cannot be used to implement private properties or methods).
1: See this es-discuss topic for some discussion about the different names.
I'm using Breeze JS to create a client-side extension property as per: http://www.breezejs.com/documentation/extending-entities
My constructor declares two camelCase properties:
function Building() {
this.fullAddress = "";
this.street = "";
}
I register the constructor with my metadata store as follows:
store.registerEntityTypeCtor("Building", Building);
I am using the camelCase naming convenvention as per: http://www.breezejs.com/documentation/naming-convention
When my Web API returns PascalCase FullAddress and Street properties, my Building entities fail to have their properties set correctly. It only works if I modify the constructor to declare client-side properties in PascalCase also.
It is my understanding that the naming convention should automatically map PascalCase server-side property names to client-side camelCase property names. Could someone please clarify this behaviour? All the other properties for my Building entity (which are not extension properties) are correctly mapped from PascalCase to camelCase.
I believe that we changed the behavior of breeze in 1.4.14 to pass unmapped properties thru the namingConvention converter, previously we did not do this. Could you try your code on 1.4.14.
On the page you are referencing it explains why -
The isBeingEdited property is only a property on the client-side
Customer entity. The "Customer" class on the server does not have an
isBeingEdited property and the backing database does not have an
isBeingEdited column in the "Customer" table either.
In your case your constructor contains properties that Breeze considers to be unmapped. The reason it works when you switch to PascalCase is a thing called chance : ) and is bad practice.
If your properties are indeed server side and you want to keep them that way then just consider renaming the properties in your constructor to match what comes back from the server.
When you run:
window.toString.call("")
everything's fine in FF/CH but in IE8 you get a script error. Investigating a bit more it turned out, that window.toString.call is undefined in IE8?
You can also run this one:
window.toString instanceof Function;
// false
alert(window.toString);
// function toString() {
// [native code]
// }
Why is that and how to solve it? And I started wondering how come jQuery works in the first place?
window is a host object, and the ECMAScript Language Specification (3rd edition) does not require host objects to be derived from the native Object object. In IE (and probably in some other browsers) host objects aren't, so they don't support any of the native methods or properties (although they may have methods or properties with the same names as native methods or properties which are accessible to scripts).
If all you want is to get hold of the language implementation's default native toString method then you should use Object.prototype.toString.call("").
NickFitz is correct, the toString method on the host object that you are finding is purely so that if you did
alert(window);
you would get the text [object]
All that the javascript method toString() used in your examples would acheive is to make a string from a string so the correct way to do what you are trying is;
var a =new String ("");
or simply
var b = "";
or if you really want to be silly;
var b = "".toString();