I am using arbor js . But when i run ie8,9 and 10 browser it show on error Object doesn't support property or method __defineGetter__ . how can i fix this problem.
__defineGetter__ is an old, proprietary way of defining property "getter" functions. If the library you're using relies on it, you can't use it on JavaScript engines that don't support it.
The modern, standard way of defining getter functions for properties doesn't use that syntax. Perhaps there's a more up-to-date version of the library you could use.
There are two/three current standard ways, and another coming:
Using get and set functions on an object initializer:
var obj = {
get foo() {
return /*...foo value...*/;
},
set foo(v) {
// Set foo value
}
};
...or using Object.defineProperty:
var obj = {};
Object.defineProperty(obj, "foo", {
get: function() {
return /*...foo value...*/;
},
set: function(v) {
// Set foo value
}
};
...or using Object.defineProperties (or the second argument to Object.create, which accepts the same thing):
var obj = {};
Object.defineProperties(obj, {
foo: {
get: function() {
return /*...foo value...*/;
},
set: function(v) {
// Set foo value
}
}
});
For objects created via constructors, ES6 will also add class:
class ThingWithFoo {
get foo() {
return /*...foo value...*/;
}
set foo(v) {
// Set foo value
}
}
Related
I have a simple object and constructor in Traditional JavaScript as follows:
function Test() {
this.data={};
}
Test.prototype={
set value(something) {
},
get value() {
return data[property];
}
};
var test=new Test();
Inside the object is another object, initially with no own properties.
I would like to write a Setter for value which sets a property on the inner object (data).
test.value.whatever=23;
Is there any way I can do this?
I expect that the Setter function could then finish the job with something like this:
set value() {
// how do I get property & value?
data[property]=value;
},
Here you go
function Test() {
this.data = {};
}
Test.prototype={
set value(v) {
this.data.whatever = v;
},
get value() {
return this.data.whatever;
}
};
var test = new Test();
test.value = 'hi';
console.log(test.value) // 'hi'
console.log(test.data) // {whatever: 'hi'}
Remember to put the data property in the constructor. Otherwise, if you put it into the prototype, it will be a shared property among every instance.
OK, I have an answer: as suggested by #Bergi & #damianmr, I used (and had to learn about) a Proxy object.
Here is a working version:
function Test() {
this.dataStore={};
this.data=new Proxy(this,{
set(target,property,value) {
target.dataStore[property]=value;
},
get(target,property) {
return target.dataStore[property];
}
});
}
Test.prototype={
};
var test=new Test();
test.data.whatever=23;
test.data.etc=46;
alert(`${test.data.whatever} ${test.data.etc}`);
As you can see:
I have an object called dataStore, and a proxy called data
The Proxy is set in the constructor
This is a simple abstracted case, but it also works for the more complex project I’m working on.
The only shortcoming is that IE doesn’t support Proxy, and the polyfills I have seen don’t like new properties.
That just means I will need to supply a functional alternative for Legacy Browsers, and wait for them to die out …
I'm having an issue with providing a static getter function for the length property of my ES6 class extends.
As it turns out the actual Function.length getter always takes precedence over my own implementation.
class Foo {
static get value() {
return 'Foo';
}
static get length() {
return this.value.length;
}
}
class Bar extends Foo {
static get value() {
return `${super.value}Bar`;
}
}
console.log(Foo.value, Foo.length); // 'Foo', 3
console.log(Bar.value, Bar.length); // 'FooBar', 0
In the example above, Foo does exactly what I expected it to do, Bar not so much. Bar.value does indeed return 'FooBar', but Bar.length being 0 surprised me.
It took me a while to realize where the 0 came from, as I fully expected it to be 6 (and would have understood 3 to some degree).
As it turns out the 0 value provided by Bar.length is in fact the length of the constructor function of Bar, I realised this when wrote the same example in ES5 notation, there is a quick way to prove this though; simply add a constructor to Bar.
class Bar extends Foo {
constructor(a, b, c, d) {
// four configured parameters
}
static get value() {
return `${super.value}Bar`;
}
}
console.log(Foo.value, Foo.length); // 'Foo', 3
console.log(Bar.value, Bar.length); // 'FooBar', 4
There are ways around this:
add the static get length() to all extends (not my idea of
inheritance)
use a different property name (e.g. static get size() works as intended, but is not a generally used property in JS)
extend the base from a built-in class which has a working length (e.g. class Foo extends Array {...}) -
None of these are what I want to do if there's a more appropriate way to do this.
So my question is; does anyone know a proper way to have a custom property override which is inherited as expected, or am I being too stubborn?
As mentioned, I figured out what went wrong by writing the class syntax to (what I believe) would be the ES5 equivalent, as it may be beneficial to other developers and may shed some light on how I think ES6 classes work I'll leave it here.
(If anyone has a tip on how to make this bit collapsable on Stackoverflow, feel free to edit/suggest)
What I suppose is happening in ES5 syntax
I am aware ES6 classes are mostly syntactic sugar around the prototypal inheritance JS has, so what seems to happen for Bar is something like;
function Foo() {}
Object.defineProperties(Foo, {
value: {
configurable: true,
get: function() {
return 'Foo';
}
},
length: {
configurable: true,
get: function() {
return this.value.length;
}
}
});
function Bar() {}
Bar.prototype = Object.create(Object.getPrototypeOf(Foo));
Object.defineProperties(Bar, {
value: {
configurable: true,
get: function() {
return 'Bar' + Foo.value;
}
}
});
console.log(Foo.value, Foo.length); // 'Foo', 3
console.log(Bar.value, Bar.length); // 'FooBar', 0
I would've expected the property descriptors of Foo to be taken into account, like:
function Bar() {}
Bar.prototype = Object.create(Object.getPrototypeOf(Foo));
Object.defineProperties(Bar, Object.assign(
// inherit any custom descriptors
Object.getOwnPropertyDescriptors(Foo),
{
configurable: true,
value: {
get: function() {
return 'Bar' + Foo.value;
}
}
}
));
console.log(Foo.value, Foo.length); // 'foo', 3
console.log(Bar.value, Bar.length); // 'bar', 6
About static members
Static members of an ES6 class are in fact members of the function object rather than its prototype object. Consider the following example, where I'll use regular methods instead of a getter, but the mechanics are identical to getters:
class Foo {
static staticMethod() {
return 'Foo static';
}
nonStaticMethod() {
return 'Foo non-static';
}
}
staticMethod will become a member of the constructor function object, whereas nonStaticMethod will become a member of that function object's prototype:
function Foo() {}
Foo.staticMethod = function() {
return 'Foo static';
}
Foo.prototype.nonStaticMethod = function() {
return 'Foo non-static';
}
If you want to run staticMethod from a Foo 'instance' you'll have to navigate to its constructor first, which is the function object where staticMethod is a member of:
let foo = new Foo();
foo.staticMethod(); // Uncaught TypeError: foo.staticMethod is not a function
// Get the static member either on the class directly
// (this works IF you know that Foo is foo's constructor)
Foo.staticMethod(); // > 'Foo static'
// this is the same, provided that neither 'prototype' nor
// 'prototype.constructor' has been overridden afterwards:
Foo.prototype.constructor.staticMethod(); // > 'Foo static'
// ...or by getting the prototype of foo
// (If you have to perform a computed lookup of an object's constructor)
// You'll want to perform such statements in a try catch though...
Object.getPrototypeOf(foo).constructor.staticMethod(); // > 'Foo static'
function.length
All functions have a length property that tells you how many arguments that function accepts:
function Foo(a, b) {}
Foo.length; // > 2
So in your example, a prototype lookup for Bar.length to Foo.length will indeed never occur, since length is already found directly on Bar. A simple override will not work:
Foo.length = 3;
Foo.length; // still 2
That is because the property is non-writable. Let's verify with getOwnPropertyDescriptor:
Object.getOwnPropertyDescriptor(Foo, 'length');
/*
{
value: 0,
writable: false,
enumerable: false,
configurable: true
}
*/
Also, instead of the value getter you define, you can instead just use function.name to get the name of a function / class constructor:
Foo.name; // > 'Foo'
Let's use this to override the length property on Foo. We are still able to override Foo.length because the property is configurable:
Object.defineProperty(Foo, 'length', {
get() {
return this.name.length;
}
});
Foo.length; // 3
This is code bloat
It is highly undesirable to have to do this for each extending class, or define a static getter for each, which is equivalent to the code above. It is not possible to entirely override the behaviour without any decoration of the function objects of some sort. But since we know that classes are just syntactic sugar, and we are actually just dealing with objects and functions, writing a decorator is easy!
function decorateClasses(...subjects) {
subjects.forEach(function(subject) {
Object.defineProperty(subject, 'value', {
get() {
const superValue = Object.getPrototypeOf(this).value || '';
return superValue + this.name;
},
enumerable: true,
configurable: true,
});
Object.defineProperty(subject, 'length', {
get() {
return this.value.length;
},
enumerable: true,
configurable: true,
});
})
}
This function accepts one or multiple objects, on which it will override the length property and set a value property. Both are accessors with a get method. get value explicitly performs prototype lookups, and then combines the results with the name of the function it belongs to. So, if we have 3 classes:
class Foo {
}
class Bar extends Foo {
}
class Baz extends Bar {
}
We can decorate all classes at once:
decorateClasses(Foo, Bar, Baz);
If we access value and length on all three classes (functions) we get the desired results:
Foo.value; // 'Foo'
Foo.length; // 3
Bar.value; // 'FooBar'
Bar.length; // 6
Baz.value; // 'FooBarBaz'
Baz.length; // 9
When using:
Object.defineProperty(obj,prop,desc){
get: function(){...
set: function(){...
}
Does the getter/setter apply to obj[prop] or does it act on obj no matter what property is specified?
I am asking because I'm trying to setup some data binding based on a nested object like:
obj[propA] = {propB:'seomthing',propC:'somethingElse'}
and when I do something like this:
var obj = {value:{propA:'testA',propB:'testB'}};
Object.defineProperty(obj.value,'propA',{
get: function(){return this.value;},
set: function(newValue){this.value=newValue;console.log('propA: ',newValue);}
});
console.log(obj.value.propA);
obj.value.propA = 'testA';
Object.defineProperty(obj.value,'propB',{
get: function(){return this.value;},
set: function(newValue){this.value=newValue;console.log('propB: ',newValue);}
});
console.log(obj.value.propB);
obj.value.propB = 'testB';
console.log('propA: ',obj.value.propA,' --propB: ',obj.value.propB);
the getter assigns the value to ALL the properties set by defineProperty within the object.
If this is the correct functionality, is there a way to have the getter/setter work only on the property defined such that in the fiddle above, propA would yield testA and propB would yield testB?
The getter and setter only apply to the named property, but this inside each one refers to the object whose property it is (you don’t have to have a backing variable for every property).
In your example, you’re always reading and modifying obj.value.value. You can create a different variable for each one by wrapping each in an IIFE, for example:
(function () {
var value;
Object.defineProperty(obj.value, 'propA', {
get: function () { return value; },
set: function (newValue) { value = newValue; },
});
})();
Updated fiddle
I have found that many javascript developers create methods that simply return a property like this :
function Obj (prop) {
this.prop = prop; // public
}
Obj.prototype.getProp = function () {
return this.prop;
};
While prop is public and can be accessed like this :
var a = obj.prop;
Moreover, I found that accessing an object property with a method is 121 times slower than accessing it directly (in Firefox)
var a, b,
obj = new Obj(1);
a = obj.prop;
// ~6ns on Chrome
// ~5ns on Firefox
b = obj.getProp();
// ~6ns on Chrome (no difference)
// ~730ns on Firefox (122x slower...)
So my question is: should we always create methods that return properties or can we access properties directly? Is that antipattern?
Yes it's an antipattern. Since js doesn't have native getters and setters which will be crossbrowser, yet, you should create your own getters and setters like:
Obj.prototype.getProp = function () {
return this.prop;
};
Yes, you still can access this prop directly, but now you doesn't have to. More on that. This way you can create private properties via closures:
function Foo() {
var __yourPrivateProp = 'Bar';
return {
getyourPrivateProp: function () {
return: __yourPrivateProp
}
};
}
I am creating an AJAX API for a web service and I want to be able to call jQuery-like accessors.
jQuery seems to be able to execute 'jQuery' as a function, but also use it to directly access the object that is the result of the function EG:
jQuery();
jQuery.each({});
This is the trick that I can't seem to pull off:
myAPI('foo'); //output: 'foo'
myAPI('foo').changeBar(); //output: 'foo' 1
myAPI.changeBar(); //Error: not a function
I have seen the answers to similar questions, which are helpful, but don't really answer my question.
#8734115 - Really interesting, but you can't access the methods that were set by f.prototype.
#2953314 - Uses Multiple operations to create object instead of a single function.
here is my code:
(function(window) {
var h = function(foo) {
// The h object is actually just the init constructor 'enhanced'
return new h.fn.init(foo);
};
/**
* Methods defined at protoype.
*/
h.fn = h.prototype = {
constructor: h,
init: function(foo) {
console.log(foo);
return this;
},
splice : function () {},
length : 0,
bar : 0,
changeBar : function() {
this.bar++;
return this.bar;
}
};
h.fn.init.prototype = h.fn;
//Publish
window.myAPI =h;
}( window));
I'm sure I'm missing something simple :(
What jQuery is doing there is using jQuery as both a function and as a pseudo-namespace. That is, you can call jQuery: var divs = jQuery("div"); and you can use properties on it, e.g.: jQuery.each(...);.
This is possible because in JavaScript, functions are first-class objects, and so you can add arbitrary properties to them:
function foo() {
alert("Foo!");
}
foo.bar = function() {
alert("Bar!");
};
foo(); // "Foo!"
foo.bar(); // "Bar!"
That's literally all there is to it.
Within the call to bar, this will be the foo function (because this is determined entirely by how a function is called, not where it's defined). jQuery doesn't use this to refer to itself (usually it uses this to refer to DOM elements, sometimes to other things like array elements; when referring to itself, since it's a single thing, it just uses jQuery).
Now, you might want to ensure that your functions have proper names (whereas the function I assigned to bar above is anonymous — the property has a name, but the function does not). In that case, you might get into the module pattern:
var foo = (function() {
function foo() {
alert("Foo!");
}
function foo_bar() {
alert("Bar!");
}
foo.bar = foo_bar;
return foo;
})();
foo(); // "Foo!"
foo.bar(); // "Bar!"
That pattern also has the advantage that you can have private data and functions held within the scoping function (the big anonymous function that wraps everything else) that only your code can use.
var foo = (function() {
function foo() {
reallyPrivate("Foo!");
}
function foo_bar() {
reallyPrivate("Bar!");
}
function reallyPrivate(msg) {
alert(msg);
}
foo.bar = foo_bar;
return foo;
})();
foo(); // "Foo!"
foo.bar(); // "Bar!"
reallyPrivate("Hi"); // Error, `reallyPrivate` is undefined outside of the scoping function
In your code, you're assigning things to the prototype property of the function. That only comes into play when the function is called as a constructor function (e.g., via new). When you do that, the object created by new receives the function's prototype property as its underlying prototype. But that's a completely different thing, unrelated to what jQuery does where it's both a function and a pseudo-namespace.
You do not need any of that weirdness, to use stuff like $.each
you just attach functions to the function object instead
of the prototype object:
function Constructor() {
if (!(this instanceof Constructor)) {
return new Constructor();
}
}
Constructor.prototype = {
each: function() {
return "instance method";
}
};
Constructor.each = function() {
return "static method";
};
var a = Constructor();
a.each(); //"instance method"
Constructor.each(); //"static method"