Why toString is not a generic function in javascript - javascript

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.

Related

How can create own call function in javascript?

As of my knowledge, in javascript there are three concepts; call, apply and bind
I want to create these function with similar behavior.
Here is a polyfill for them (not accurate though, just what came into my mind):
Function.prototype.call = function(context, ...args) {
const fn = Symbol();
try {
context[fn] = this;
return context[fn](...args);
} catch(e) {
// Turn primitive types into complex ones 1 -> Number, thanks to Mark Meyer for this.
context = new context.constructor(context);
context[fn] = this;
}
return context[fn](...args);
};
Function.prototype.apply = function(context, args) {
return this.call(context, ...args);
};
Function.prototype.bind = function(context, ...args) {
return (...args2) => this.call(context, ...args, ...args2);
};
The only thing that is impossible to polyfill is fn.call(null), as that primitive can't be turned into a complex type, only native code can do this
Add your own call function like "_call"
Function.prototype._call = function(newcontext, ...arg){
var demoFn = new Function('tempfuncton', 'tempthis','arg' , '{ tempthis["f"]=tempfuncton; return tempthis.f(arg);}');
demoFn(this,newcontext,arg);
}
write a demo function
function anyfunction(args){
console.log(this,args)
}
call it like previous. First argument should be an object. Otherwise write a code to convert it into object.
anyfunction._call({'mm':'my provided this object'},"arg1","arg2")
function B(a,b,c){
console.log(a,b,c)
}
Function.prototype.OwnCallFunction = function(){
if( this.length == arguments.length)
this(...arguments)
else
console.error('Signature does not match')
}
B.OwnCallFunction(323,34,34)
I followed this approach to create own call function. With help of Function
Constructor, I add a function to it and it worked on firefox.
New approach, with more clarity
Function.prototype.call2 = function(context, ...args){
console.log(context)
const fn = Symbol();
context[fn] = this;
context[fn](...args);
}
In above answers I can see that spread operators has been used, but if we really want to make pollyfill of call then we should avoid spread
operator and latest concept of es6.I am sharing solution without es6.
Call Function:-
Function.prototype.myCall = function(obj) {
obj = obj || global;
var id = "00" + Math.random();
while (obj.hasOwnProperty(id)) {
id = "00" + Math.random();
}
obj[id] = this;
let arg=[];
for(let i=1;i<arguments.length;i++){
arg.push("arguments[" + i + "]");
}
result= eval("obj[id]("+arg+")");
delete obj[id];
return result;
}
Apply function:-
Function.prototype.myApply = function(obj, argArr) {
obj = obj || global;
var id = "00" + Math.random();
while (obj.hasOwnProperty(id)) {
id = "00" + Math.random();
}
obj[id] = this;
let arg=[];
let result
if(!argArr){
result= obj[id].fn();
}
else{
for(let i=0;i<argArr.length;i++){
arg.push("argArr[" + i + "]");
}
result= eval("obj[id]("+arg+")");
delete obj[id];
}
return result;
}
Bind function:-
Function.prototype.myBind2= function(){
let obj1= this;
const obj= Array.prototype.slice.call(arguments,0,1);
const arg= Array.prototype.slice.call(arguments,1);
return function(){
const arg2= Array.prototype.slice.call(arguments);
obj1.apply(obj[0],Array.prototype.concat(arg, arg2));
}
Another solution Bind: we can pass object argument of function
Function.prototype.myBind2 = function(obj) {
let fn = this;
const arg = Array.prototype.slice.call(arguments, 1);
return function() {
const arg2 = Array.prototype.slice.call(arguments);
fn.apply(obj, Array.prototype.concat(arg, arg2));
}
While each browser has its own source code for implementing Javascript, you can find how many of the native Javascript functions are implemented with the ECMA specifications found here:
http://www.ecma-international.org/ecma-262/10.0/index.html#sec-properties-of-the-function-prototype-object
For specs of apply, see: 19.2.3.1
For specs of bind, see: 19.2.3.2
For specs of call, see: 19.2.3.3
If you're interested for example, how Node implemented apply, you can dig into their source code on Github here: https://github.com/nodejs/node
Here is my sweet and simple solution. We are adding the ObjRef in prototypal chain to avoid any name conflicts with other properties
Function.prototype.call2 = function (objRef, ...args) {
otherObj = Object.create(objRef)
otherObj[this.name] = this;
otherObj[this.name](...args);
}
I don't think using Object.create makes sense here as when you will console this inside the function you won't see the desired object.
Here is my try(not accurate though) but will work.
Function.prototype.myCall = function (thisContext, ...param) {
let name = this.name;
thisContext[name] = this;
thisContext[name](...param);
}
Function.prototype.mycall = function(context, ...args){
context.fun= this; //add personal function to context
context.fun(...args);
}
function personal (msg){
alert(this.name + " " + msg);
}
let obj = {
name:'Ajinkya'
}
personal.mycall(obj,'Khandar'); // pass object and args in mycall

JavaScript Chainable Method Delimma

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'

Creating method for string without creating prototype

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'

A javascript function that has a defined function

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

Is there a difference between using "this" and "prototype" in Javascript here?

Is there a difference between the two codes below, I presume not.
function Agent(bIsSecret)
{
if(bIsSecret)
this.isSecret=true;
this.isActive = true;
this.isMale = false;
}
and
function Agent(bIsSecret)
{
if(bIsSecret)
this.isSecret=true;
}
Agent.prototype.isActive = true;
Agent.prototype.isMale = true;
There is a difference at least if you are assigning a non-primitive object to this.somevar or prototype.somevar.
Try running this:
function Agent(bIsSecret)
{
if(bIsSecret)
this.isSecret=true;
this.isActive = true;
this.isMale = false;
this.myArray = new Array(1,2,3);
}
function Agent2(bIsSecret)
{
if(bIsSecret)
this.isSecret = true;
}
Agent2.prototype.isActive = true;
Agent2.prototype.isMale = true;
Agent2.prototype.myArray = new Array(1,2,3);
var agent_a = new Agent();
var agent_b = new Agent();
var agent2_a = new Agent2();
var agent2_b = new Agent2();
if (agent_a.myArray == agent_b.myArray)
alert('agent_a.myArray == agent_b.myArray');
else
alert('agent_a.myArray != agent_b.myArray');
if (agent2_a.myArray == agent2_b.myArray)
alert('agent2_a.myArray == agent2_b.myArray');
else
alert('agent2_a.myArray != agent2_b.myArray');
No. 'prototype' used for implementing inheritance in Javascript. Such as that:
/** obsolete syntax **/
var Person = Class.create();
Person.prototype = {
initialize: function(name) {
this.name = name;
},
say: function(message) {
return this.name + ': ' + message;
}
};
var guy = new Person('Miro');
guy.say('hi');
// -> "Miro: hi"
var Pirate = Class.create();
// inherit from Person class:
Pirate.prototype = Object.extend(new Person(), {
// redefine the speak method
say: function(message) {
return this.name + ': ' + message + ', yarr!';
}
});
var john = new Pirate('Long John');
john.say('ahoy matey');
// -> "Long John: ahoy matey, yarr!"
code source and additional info you can find here: http://www.prototypejs.org/learn/class-inheritance
Functionally, this is the same. The latter, however, emphasizes similarities between Agent objects. You can see in a glimpse that these members have that value, while in a more complicated constructor function, with lots of conditionals, it's harder.
It also allows the javascript runtime to choose how it handles Agent member initializations. (do some precompilation, ...)
Assuming that this function is to be used as a constructor, the first with set properties on the new instance and the second on the prototype. If they are independent of the instance the two snippets are equivalent, but if they aren't (as their name suggest), then they are not.

Categories