I have 2 methods that I'd like to use as chainable methods. Other methods may be chained to further modify text.
left returns X characters from the left.
right returns X characters from the right.
Currently I can do this:
var txt = "hello";
S$(txt).left(4).right(2).val //returns "ll"
What I want to do is this.
Basically I want to return the results after the last chained method without having to call the property. Is this possible?
var txt = "hello";
S$(txt).left(4).right(2) //returns "ll"
Below is the main code:
(function (global) {
var jInit = function(text){
this.text = text;
this.val = text;
}
var jIn = function(text){
return new jInit(text);
}
var jStringy = jStringy || jIn;
jInit.prototype.left = function (num_char) {
if (num_char == undefined) {
throw "Number of characters is required!";
}
this.val = this.val.substring(0, num_char);
return this;
}
jInit.prototype.right = function (numchar) {
this.val = this.val.substring(this.val.length - numchar, this.val.length);
return this;
}
global.jStringy = global.S$ = jStringy;
return this;
}(window));
You can override valueOf and toString methods of Object to archieve it.
Example:
var myObject = {
value: 5,
valueOf: function(){
return this.value;
},
toString: function() {
return 'value of this object is' + this.value;
}
};
As Javascript is a duck typing language, nothing will prevent you from performing mathematical operations and string concatenation against primitive values/objects as these methods are called during expression evaluation process no matter where they came from.
Examples:
console.log(myObject + 10);
will print 15
alert(myObject);
will print 'value of this object is 5'
Related
So i have to write a program, which could chain function like this:
name("Adam").place("cinema").movie("xxx") expected output should be like this: Adam goes to Cinema to watch movie called xxx, what i have so far:
var test = function(name){
var self = {};
console.log(name)
function someFunc(where) {
console.log("goes to cinema" + where)
return self;
}
function someOtherFunc(what) {
console.log("to watch movie" + what)
return self;
}
self.someFunc = someFunc;
self.someOtherFunc = someOtherFunc;
return self;
}
console.log(test("Adam").someFunc("cinema").someOtherFunc("xxx"));
But it gives me strings in different lines, and i want to be it in one sentence, any help will be appreciated.
You can do something like this:
var test = function(message) {
this.someFunc = function(where) {
message += ` goes to ${where}`;
return this; // Allow chaining
}
this.someOtherFunc = function(what) {
message += ` to watch movie ${what}`;
return this; // Allow chaining
}
this.value = function() {
return message; //End chain
}
return this; // Start chain
}
console.log(test("Adam").someFunc("cinema").someOtherFunc("xxx").value());
//Adam goes to cinema to watch movie xxx
Edit:
Is it possible to get that result without .value() ?
You can override .toString().
Every object has a toString() method that is automatically called when
the object is to be represented as a text value or when an object is
referred to in a manner in which a string is expected. By default, the
toString() method is inherited by every object descended from Object.
If this method is not overridden in a custom object, toString()
returns "[object type]", where type is the object type.
This would require to convert the object to string though.
var test = function(message) {
this.someFunc = function(where) {
message += ` goes to ${where}`;
return this;
}
this.someOtherFunc = function(what) {
message += ` to watch movie ${what}`;
return this;
}
this.toString = function() {
return message;
}
return this;
}
console.log(`${ test("Adam").someFunc("cinema").someOtherFunc("xxx")}`);
Assuming you need your functions to execute in that order, and produce a sentence that doesn't vary in order, you could do the following:
var test = function(name){
var self = {
message: name,
};
function someFunc(where) {
self.message += " goes to cinema" + where;
return self;
}
function someOtherFunc(what) {
self.message += " to watch movie" + what;
console.log(self.message);
}
self.someFunc = someFunc;
self.someOtherFunc = someOtherFunc;
return self;
}
console.log(test("Adam").someFunc("cinema").someOtherFunc("xxx"));
I was trying to do something like this.
var myFunc = function() {}
myFunc.prototype = new String();
myFunc.prototype.replace = function() {return 'hii, Mr '+ this.toString();}
var oVal = new myFunc('Jyotirmay');
oVal.replace();
o/p :: Uncaught TypeError: String.prototype.toString is not generic(…)
Why "function not generic" error comes actually in general?
As to be more clear, How can i pass my argument i.e Jyotirmay from inherited class to base class i.e string. So that i can get that value by calling any proper string function.
I don't want to get my passed value from my function by handling that variable in it.
I want that to be handled by parent class. You can say super() in other languages.
It is unclear what exactly you are trying to achieve from your question and comments, but perhaps this is all you are trying to do?
function myFunc(inputArg) {
this.inputArg = inputArg;
}
myFunc.prototype = {
replace: function () {
return 'hii, Mr ' + this.inputArg;
},
toString: function () {
return '' + this.inputArg;
}
};
myFunc.prototype.valueOf = myFunc.prototype.toString;
function log(inputArg) {
document.getElementById('out').appendChild(document.createTextNode(inputArg + '\n'));
}
var oVal = new myFunc('Jyotirmay');
log(oVal);
log(oVal.replace());
<pre id="out"></pre>
As to Why is toString not generic, this is because not all objects can be represented as a string by the same conversion method.
Update based on your latest comment
Native objects are notoriously difficult, if not impossible, to subclass in Javascript. There are a few hacks that will allow you partial success, but I would not recommend them and good luck across different environments.
Two (but not the only) such hacks are:
Stealing from an iframe
function stealObject(objectName, myVariableName) {
var iframe = document.createElement('iframe');
iframe.style.display = 'none';
iframe.src = 'javascript:parent.' + myVariableName + ' = ' + objectName;
document.body.appendChild(iframe);
document.body.removeChild(iframe);
return window[myVariableName];
}
function log(inputArg) {
document.getElementById('out').appendChild(document.createTextNode(inputArg + '\n'));
}
try {
stealObject('String', 'MyString');
MyString.prototype.replace = function () {
return 'hii, Mr ' + this;
};
var oVal = new MyString('Jyotirmay');
log(oVal);
log(oVal.toUpperCase());
log(oVal.replace());
} catch (e) {
log(e);
}
<pre id="out"></pre>
Doesn't work in SO snippets because SecurityError: Sandbox access violation: but can see it on this jsFiddle. typeof oVal will return object and not string and oVal instanceof String will be false. oVal.constructor === String will return false.
Another hack
function MyString() {
this.str = '' + arguments[0];
};
with(MyString.prototype = new String()) {
toString = valueOf = function () {
return this.str;
};
}
MyString.prototype.replace = function () {
return 'hii, Mr ' + this;
};
function log(inputArg) {
document.getElementById('out').appendChild(document.createTextNode(inputArg + '\n'));
}
var oVal = new MyString('Jyotirmay');
log(oVal);
log(oVal.toUpperCase());
log(oVal.replace());
<pre id="out"></pre>
The magic length property is broken in this one and you would need to call oVal.toString().length instead. typeof oVal will return object and not string but oVal instanceof String will be true. oVal.constructor === String will return true.
I want to create a method that you can call like 'string'.doSth() without creating a new string prototype. How can I do it?
I noticed you DON'T want String.prototype
Avoid using it by doing something like:
window.doSth = function (s) {
return s + '!';
};
Or, you can make your own constructor:
var SpecialString = function (s) {
this.value = s;
this.doSth = function () {
return this.value + '!';
};
};
Now:
var myString = new SpecialString('Foo');
myString.value; // Its value, Foo
myString.doSth(); // Returns Foo!
I'll leave the rest just in case you change your mind
this and String.prototype
You can use String.prototype. This will let you "add functions" to string. To get the string, use this:
String.prototype.doSth = function () {
alert(this);
};
var testString = 'Foo Bar';
testString.doSth(); // Alerts "Foo Bar"
Using return
Use return to produce a new value. Let's say you wanted this function to add an exclamation mark ! to the end of the string:
String.prototype.addExclamation = function () {
return this + '!';
};
Now:
var testString = "Foo";
var newString = testString.addExclamation();
alert(newString); // Alerts Foo!
Only other way is to just not create a global function and add it to String
String.doSth = function(str) {
//do something
}
String.doSth('hi');
You can allways augment the prototype of String. Here's how
String.prototype.doSomething = function () {
console.log('doing something');
}
var a = 'str';
a.doSomething();
By writing 'string' you are basically creating a new string object.
If you add a doSth method to the string prototype, it will be callable:
String.prototype.doSth = function doSth() {
console.log('Inside');
}
"string".doSth(); // will log 'Inside'
Thanks for reading.
So I am working on a my first node.js app. I'm relatively familiar with javascript but not well enough.
I have declared a class FOO with a method called bars(index, value} that accepts 2 params. In order do use this, after creating an instance, I have the following fooInstance.bars(3, 2)
I would like to call this method a bit differently. How can I change my FOO definition so that I can use it like this fooInstance.bars(3).value?
My current code is below
var util = require('util'),
events = require('events');
var FOO = function(opts) {
this.ipAddress = opts.ipAddress;
this.port = opts.port;
};
FOO.prototype = new events.EventEmitter;
module.exports = FOO;
FOO.prototype.bars = function (index, value) {
switch(index) {
case 1:
console.log("Apple " + " at " + value)
break;
case 2:
console.log("Banana, " + " at " + value)
break;
case 3:
console.log("Cherry, " + " at " + value)
break;
case 4:
console.log("Date, " + " at " + value)
break;
default:
break;
}
}
thanks in advance!
It is called Method Chaining or sometimes Fluent interface. The main idea behind the 'chaining' is to return an object (often times self) as a result, enabling direct invocation on the returned value.
I copied a sample code from here (attribute goes to the original author) that returns self as a return value.
var obj = {
function1: function () {
alert("function1");
return obj;
},
function2: function () {
alert("function2");
return obj;
},
function3: function () {
alert("function3");
return obj;
}
}
obj.function1().function2().function3();
For your FOO implementation, try returning this at the end of bars function.
FOO.prototype.bars = function(index,value){
// your previous code here;
this.value = value;
return this;
}
You are not asking for method chaining. More like
> console.log(fooInstance.bars(3).value)
> Cherry
then do the following:
var util = require('util'),
events = require('events');
var FOO = function(opts) {
this.ipAddress = opts.ipAddress;
this.port = opts.port;
};
FOO.prototype = new events.EventEmitter;
module.exports = FOO;
FOO.prototype.bars = function (index) {
var undef;
switch(index) {
case 1:
return { value : 'Apple' };
case 2:
return { value : 'Bannana' };
case 3:
return { value : 'Cherry' };
case 4:
return { value : 'Date' };
default:
return { value : undef };
}
}
I'm not exactly sure if you wanted a string back as a value but just guessing. This will return an object as an answer which then can be used like ".value".
What I do to case statements that is simpler is this:
var easierThanCase = {
'1' : 'Apple',
'2' : 'Bannana',
'3' : 'Cherry',
'4' : 'Date'
};
return { value : easierThanCase[index+''] };
You have two possibilities:
You can simply pass the arguments you need. Javascript will set arguments not used to undefined. Then, in the function, you can check by if (!value) or if (typedef value === "undefined") to find the state. (Javascript is in general very flexible here. You can also get arguments you pass but you didn't declare in the function definition).
You can create a new function bars() even though the name has already been used. But doing so will destroy the old function.
In order to check 1, try this:
var test = new FOO();
console.log(test.bars(3));
It'll anwer: Cherry, at undefined
In order to check 2, add after the definition of bars:
FOO.prototype.bars = function(index) {
console.log("In new bars!");
}
Here are more infos, also about the keyword arguments:
How to get function parameter names/values dynamically from javascript
Here is a better way to implement your bars method:
FOO.prototype.bars = function (index, value) {
var fruitArray = ["Apple", "Banana", "Cherry", "Data"];
console.log(fruitArray[index - 1] + " at " + value);
}
If you are wanting to do this: fooInstance.bars(3).value. You are calling bars with one parameter (index === 3) and then calling the property of value on this result. This logic does not make much sense in this example. Hope this helps.
I am trying you get a better understanding of JavaScript, especially the prototype functionality. I am having trouble with this case:
I am trying to define a function someObject with a type function so that it will behave like the following:
var myTestObject = someObject();
If I call:
myTestObject() ===> "The object is initailType"
and then when this is called
myTestObject.type() ===> "InitialType"
Then if I make this call
myTestObject.type("newtype")
myTestObject.type() ===> "newType"
A call to
myTestObject() ===> "The Object is newType".
I have tried both this How does JavaScript .prototype work?
and this How do you create a method for a custom object in JavaScript?
,but I am getting several different errors depending on how it is implemented, mostly this though (Uncaught TypeError: Object myTestObject has no method 'type'). I feel like I am making this harder then it should be.
edit: more code.
function box(){
var _current = "initialType"
Object.defineProperty(this, "current", {
get: function(){return _current;},
set: function(value){
if(arguments.length === 1){
_current = value;
} }
})
return "The Object is " + this.type(this.current)
}
box.prototype.type = function(newValue){
var type = null;
if(arguments.length == 0){
type = "initialType";
}else {
type = newValue
}
return type
}
I would use something like this:
function Box(){}
Box.prototype.type = "initialType";
Box.prototype.toString = function() {
return "The Object is " + this.type + ".";
};
And use it like this:
var b = new Box();
b.type; // "initialType"
b + ''; // "The Object is initialType."
b.type = 'otherType'; // "otherType"
b.type; // "otherType"
b + ''; // "The Object is otherType."
This does what you've asked, but I don't understand what you want to do with the prototype, so this code doesn't use that. For example, the sample code doesn't use new, so the return value of someObject won't use its prototype.
function someObject()
{
var currentType = "initailType";
var formatter = function() {
return "The object is " + currentType;
};
formatter.type = function(value) {
if (arguments.length == 0) {
return currentType;
} else {
currentType = value;
}
};
return formatter;
}
var myTestObject = someObject();
myTestObject(); // => "The object is initailType"
myTestObject.type(); // => "initialType"
myTestObject.type("newType");
myTestObject.type(); // => "newType"
myTestObject(); // => "The object is newType".
see demo
Edit: example using prototype and new.
function Box() { // class name starts with a capital letter
this._type = "initialType"; // set up default values in constructor function
} // no "return" in constructor function, using "new" handles that
Box.prototype.type = function(value) { // adding method to the prototype
if (arguments.length == 0) { // magic arguments local variable...
return this._type; // initially returns the value set in the constructor
} else {
this._type = value; // update the stored value
}
};
Box.prototype.format = function() // another method on the box, rather than a return from the constructor
{
return "The object is " + this.type(); // could use this._type instead
};
var box = new Box(); // instance variable with lowercase name
console.log(box.type()); // read the default value
console.log(box.format()); // print the message with the initial value of type
box.type("another type"); // set the type property, no return value
console.log(box.format()); // print the new message