Here is the situation: I have checking on existing class like:
('Promise' in window) // true/false`
And I wanna force return false or true on it, can I do it?
Yes, I can check it by some other way, like `
window.Promise = undefined;
window.Promise === undefined;
Or something like this, but can I somehow delete this object or simulate something for 'in' operator?
I check specification and v8 code, there is 'in' operator just call 'HasProperty' operator, which realization on c++.. I know 'hack' with faking toString/valueOf methods:
obj = {
toString: function(){ return 'myName'; }
},
obj2 = {};
obj2[obj] = 1; // Object {myName: 1}
May be I can use it in some way? But, as I send string 'Promise' I can't just fake it like this way.. may be exist some way to fake 'HasProperty'?
Related
Working on an E2E using Ramda. I'm not getting how to convert a simple IF condition using Ramda Cond.
Code using If :
if (constraint == 'required') {
// then only do something
await waitForElementToBeClickable(constraintElement);
await constraint.click();
}
I don't want the else because I want the action to happen only if the constraint is present.
I've done this so far using constraint but it's not working :
await waitForElementToBeClickable(cond([
[equals('required'), always(constraintElement)],
])(constraint), this.browser);
const constraintCheck = cond([
[equals('required'), () => constraintElement.click()],
]);
await constraintCheck(constraint);
In some cases, I do not want to pass the constraint. Then the Condition should not execute at all. But it is always getting executed and throwing the error : Cannot read property 'isPresent' of Undefined.
I think perhaps there's some confusion here (beyond what customcommander rightly points out about the type of constraint.)
One of the features Ramda tries to offer is to allow us to program with expressions rather than statements. Especially concerning are control-flow statements. But a statement that looks like this:
let foo
if (condition) {
foo = 'bar'
} else {
foo = 'baz'
}
already has a standard expression form:
const foo = condition ? 'bar' : 'baz'
Ramda does not really try to offer an alternative to this. But there is another way we might try to use if:
let foo
if (test(val)) {
foo = bar(val)
} else {
foo = baz(val)
}
Here, when working with functions, Ramda offers a convenient shorthand:
const getFoo = ifElse(test, bar, baz)
// ... later
const foo = getFoo(val)
(And if you just want to return val in the case the test fails, you can use the shorthand:
const foo = when(test, bar)
Or if you want val when the test succeeds, you can do
const foo = unless(test, baz)
)
While it might be slightly more expressive to turn the code into
const foo = ifElse(test, bar, baz)(val)
That's not the main point. The rationale for ifElse is to use it in creating the reusable function ifElse(test, bar, baz). (cond is just the same, just offering a sequence of condition-consequent pairs instead of one if and one else.)
Note one important feature to this: the test function, the function to run if it's true, and the one to run if it's false all have the same signature. If one of them takes three parameters, then they all should accept three parameters. And while the test should return a boolean, the other two can have any return type, but each should have the same return type as the other.
So one can use a thunk, as you try with () => constraintElement.click(), it is mostly a misuse of the Ramda feature. It probably gains you nothing in your code.
It's still not clear what you're trying to do with the conversion from an if statement to ifElse or cond. Please feel free to add an update to your question explaining more fully what you're trying to do, and what problem you're trying to solve with this conversion, someone will probably be able to offer some help. But make sure you clarify what constraint and constraintElement are and what waitForElementToBeClickable resolves to. Right now it's fairly confusing.
By looking at your example, it seems that you use constraint both as a string and an object which may cause unnecessary confusion. I know you can implement a toString() method on an object but I'm not sure if that always plays nicely when you integrate with external libraries
const obj = {
toString: () => 'burrito',
order: () => '🌯'
};
obj + '' === 'burrito' // true
obj === 'burrito' // false
equals('burrito', obj + '') // true
equals('burrito', obj) // false
I would suggest that you convert your object into a string before you make the check:
const check = pipe(
toString,
equals('burrito')
);
check(obj); // true
Then if you don't need an "else" branch, you could consider using when.
const execute = when(check, invoker(0, 'order'))
execute(obj); // "🌯"
execute({}); // {}
Suppose I am trying to assign a variable in a way that causes an exception
I am going to access a non-existent key of a dictionary:
myObject.property = dictionary['NO_KEY'][0];
Now, because 'NO_KEY' does not exist on dictionary, my program will catch an exception when trying to subscript 0 of undefined - and crash. Is it possible to execute this line above as a no-op so that my script can continue running? I know there is try-catch syntex, but is there a more elegant syntax with ESMA6?
You can use an if condition and statement, Object.hasOwnProperty() or as suggested by #Ryan in operator
if (dictionary.hasOwnProperty("NO_KEY")) {
myObject.property = dictionary["NO_KEY"][0];
}
if ("NO_KEY" in dictionary) {
myObject.property = dictionary["NO_KEY"][0];
}
Object.defineProperty(Object.prototype,
'accessWithSilentFail', {
configurable: false,
enumerable: false,
writable: false,
value: function(key) {
return this[key] ? this[key] : {};
}});
myObject.property = dictionary
.accessWithSilentFail('NO_KEY')
.accessWithSilentFail(0);
That way you get an empty object if at any point the chain fails. You need to get an object so the chain doesn't fail halfway. You can call the function something shorter if you're going to use it a lot.
Although this works, it has many, many limitations, and it changes the Object prototype, which is usually frowned upon. You really should consider just checking for undefined, which is the idiomatic way to do it.
If you ever need to check if the access chain failed, you can use:
function chainFailed(result) {
return Object.keys(result).length === 0;
}
So you could do
myObject.property = dictionary
.accessWithSilentFail('NO_KEY')
.accessWithSilentFail(0);
if (!chainFailed(myObject.property)) {
//keep on
} else {
//handle failure
}
This works as long as your expected return isn't an empty object, on which case chainFailed will always return true. But I'm assuming you really want to fail silently, because if you wanted to handle errors you could just use an exception.
Use ternary operator
myObject.property = dictionary['NO_KEY'] ? dictionary['NO_KEY'][0] : null;
While I believe this is a bad idea that will come back to bite you later, here is a solution for modern browsers using proxies. Yes, you are still checking for the property existence, but it is hidden from your code accessing the dictionary keys.
var dictionary = {a: 42};
dictionary = new Proxy(dictionary, {
get: (target, property) => {
if (target.hasOwnProperty(property)) {
return target[property];
}
return {};
}
});
// Existing properties are passed through unchanged
console.log(dictionary.a);
// Missing properties result in an empty object
console.log(dictionary.b);
// Original test
var lost = dictionary['NO_KEY'][0];
console.log(lost);
Provided that the object MAY contain own property called "hasOwnProperty":
> a={abc: 123};
{ abc: 123 }
> a.hasOwnProperty("abc");
true
> a['hasOwnProperty'] = 1;
1
> a.hasOwnProperty("abc");
TypeError: a.hasOwnProperty is not a function
...
This works, kinda ugly interface, if you think about Object.keys(), Object.assign() ETC.. So, is there a better way?
> Object.hasOwnProperty.call(a, "abc");
true
> Object.hasOwnProperty.call(a, "hasOwnProperty");
true
And why shouldn't the solution be the only recommended way? Using methods directly from an object seems like a recipe for a failure, especially if it is containing external data (not in one's control)
The appropriate/recommended way to use hasOwnProperty is as a filter, or a means to determine whether an object... well, has that property. Just they way you are using it in your second command a.hasOwnProperty('abc').
By overwriting the Object hasOwnProperty property with a['hasOwnProperty'] = 1, while it's safe and valid, just removes the ability to use the hasOwnProperty function on that Object.
Am I missing your true question here? It seems like you already knew this from your example.
By
'using methods directly from an object seems like a recipe for a failure
are you referring to something like this:
> dog = {speak: function() {console.log('ruff! ruff!')}};
> dog.speak(); // ruff! ruff!
Because that is extremely useful in many ways as you can imagine.
If you can use ECMAScript 2015 you can try Reflect.getOwnPropertyDescriptor.
It returns a property descriptor of the given property if it exists on the object, undefined otherwise.
To simplify you can create this function:
var hasOwnProp = (obj, prop) => Reflect.getOwnPropertyDescriptor(obj, prop) !== undefined;
var obj = new Object();
obj.prop = 'exists';
console.log('Using hasOwnProperty')
console.log('prop: ' + obj.hasOwnProperty('prop'));
console.log('toString: ' + obj.hasOwnProperty('toString'));
console.log('hasOwnProperty: ' + obj.hasOwnProperty('hasOwnProperty'));
var hasOwnProp = (obj, prop) => Reflect.getOwnPropertyDescriptor(obj, prop) !== undefined;
console.log('Using getOwnPropertyDescriptor')
console.log('prop: ' + hasOwnProp(obj, 'prop'));
console.log('toString: ' + hasOwnProp(obj, 'toString'));
console.log('hasOwnProperty: ' + hasOwnProp(obj, 'hasOwnProperty'));
obj['hasOwnProperty'] = 1;
console.log('hasOwnProperty: ' + hasOwnProp(obj, 'hasOwnProperty'));
Any built-in can be overridden in JS - it's generally considered best practice to avoid overriding any native methods where possible. If the original functionality is preserved it's OK as it will still behave as expected and even could possibly extended further if overridden correctly again.
As that's considered best practice I recommend either remapping the keys to avoid overriding them. If remapping the keys is not an option then you can maybe make it feel a little less messy by either locally referencing/wrapping Object.hasOwnProperty or Object.prototype.hasOwnProperty. In the case of hasOwnProperty you could possibly implement an iterator (as iterating over enumerable non-inherited properties is a very common use of hasOwnProperty) method to reduce the likelihood of its use. There's always still the risk of someone less familiar with your object attempting to directly iterate so I really feel that key mapping is the safer bet even if it does cause a slight difference in between server-side keys and local ones.
A key mapping could be as simple as a suffix using hasOwnProperty_data instead of hasOwnProperty this would mean objects would behave as expected and your IDE's autocomplete likely will still be close enough to know what the property represents.
A mapping function might look like the following:
function remapKeys(myObj){
for(var key in myObj){
if(Object.prototype.hasOwnProperty.call(myObj, key)){
if((key in Object) && Object[key] !== myObj[key]){ // Check key is present on Object and that it's different ie an overridden property
myObj[key + "_data"] = myObj[key];
delete myObj[key]; // Remove the key
}
}
}
return myObj; // Alters the object directly so no need to return but safer
}
// Test
var a = {};
a.hasOwnProperty = function(){ return 'overridden'; };
a.otherProp = 'test';
remapKeys(a);
console.log(a); // a { hasOwnProperty_data : function(){ return 'overridden';}, otherProp: 'test' }
console.log(a.hasOwnProperty('otherProp')); // true
I'm referring to the testing assertion library : http://chaijs.com/api/bdd/#false
You can write language chain assertions like the following:
expect(false).to.be.false;
expect() is obviously a global function, "to.be" looks like two properties, but how does the last part "false" work. I'm expecting that it would have to be a function call:
expect(false).to.be.false();
Is this 2015 ES syntax? I can't seem to find a reference to it in https://github.com/lukehoban/es6features
Stack Overflow says its not possible: How to implement optional parentheses during function call? (function overloading)
Can anyone shed some light on how something like this is implemented ?
Source Code: https://github.com/chaijs/chai/blob/master/lib/chai/core/assertions.js#L281
You can do this (and a lot of other stuff) with Object.defineProperty. Here's a basic example:
// our "constructor" takes some value we want to test
var Test = function (value) {
// create our object
var testObj = {};
// give it a property called "false"
Object.defineProperty(testObj, 'false', {
// the "get" function decides what is returned
// when the `false` property is retrieved
get: function () {
return !value;
}
});
// return our object
return testObj;
};
var f1 = Test(false);
console.log(f1.false); // true
var f2 = Test("other");
console.log(f2.false); // false
There's a lot more you can do with Object.defineProperty. You should check out the MDN docs for Object.defineProperty for detail.
I like how Ruby's .tap method works. It lets you tap into any method chain without breaking the chain. I lets you operate an object then returns the object so that the methods chain can go on as normal. For example if you have foo = "foobar".upcase.reverse, you can do:
"foo = foobar".upcase.tap{|s| print s}.reverse
It will print the upcased (but not reversed) string and proceed with the reversing and assignment just like the original line.
I would like to have a similar function in JS that would serve a single purpose: log the object to console.
I tried this:
Object.prototype.foo = function() {
console.log(this);
return this;
};
Generally, it works (though it outputs Number objects for numbers rather than their numeric values).
But when i use some jQuery along with this, it breaks jQuery and stops all further code execution on the page.
Errors are like this:
Uncaught TypeError: Object foo has no method 'push'
Uncaught TypeError: Object function () { window.runnerWindow.proxyConsole.log( "foo" ); } has no method 'exec'
Here's a test case: http://jsbin.com/oFUvehAR/2/edit (uncomment the first line to see it break).
So i guess that it's not safe to mess with objects' prototypes.
Then, what is the correct way to do what i want? A function that logs current object to console and returns the object so that the chain can continue. For primitives, it should log their values rather than just objects.
You correctly figured out how a method can be safely added anywhere in a chain, but your adding it to the Object.prototype is intrusive and can break code easily. Looks like jQuery code is the one that breaks for you.
A much safer way is:
Object.defineProperty(Object.prototype, 'foo', {
value : function() { console.log( "foo" ); return this; },
enumerable : false
});
DEMO: http://jsbin.com/oFUvehAR/7/edit
Finally, something generic could look like this:
Object.defineProperty(Object.prototype, 'tap', {
value : function(intercept) {
intercept.call(this);
return this;
},
enumerable : false
});
// Usage:
var x = { a:1 };
x.tap(function(){ console.log(this); });
As for the primitives part of your question, that is a bit trickier. When you call the tap method on a primitive, an Object wrapper is created and the tap method is called on it. The primitive value is still available, via the valueOf() method of that Object wrapper, so you could log it. The tricky part is that you have no way of knowing if the "thing" that you wanted to call the tap method on was initially a primitive or an Object wrapper. Assuming you never want to work with Object wrappers (that is quite reasonable), you could do the better tap method posted below.
Object.defineProperty(Object.prototype, 'tap', {
value : function(intercept) {
var val = (this instanceof Number || this instanceof String || this instanceof Boolean) ? this.valueOf() : this;
intercept(val);
return val;
},
enumerable : false
});
var log = console.log.bind(console);
var x = { a : 1 };
x.tap(log);
2.0.tap(log);
Notice that while in the first version of the tap function, the function passed to it had the useful information in this, in the second version it is mandatory to pass it as a parameter.
If you want a specialized logger for it, you can do something like this:
Object.defineProperty(Object.prototype, 'log', {
value : function(){
return this.tap(console.log.bind(console));
},
enumerable : false,
writable : true /* You want to allow objects to overwrite the log method */
});