JavaScript return a default value - javascript

I want to make a library of functions like this (similar to what jquery is doing)
var myLib = function (idOfAnElement){
var myElement = document.getElementById(idOfAnElement);
return{
getHeight: function (){
return myElement.style.height;
},
getWidth: function (){
return myElement.style.width;
}
}
}
My problem is, that I don't know how to return
myElement
by default, if there is no other function called like
myLib('myId').getHeight; // Returns Height
myLib('myId') // Is supposed to return the HTML-Element with id = 'myId'

Create a privileged method returning the value of private myElement property itself
var myLib = function (idOfAnElement){
var myElement = document.getElementById(idOfAnElement);
return{
getHeight: function (){
return myElement.style.height;
},
getWidth: function (){
return myElement.style.width;
},
getElement: function() {
return myElement;
}
}
}
myLib('myId').getElement();

What you want can be achieved simply by adding the methods you want to the element object,
Javascript allows easy adding methods to existing objects, even the this pointer will point to the bound object.
var myLib = function (idOfAnElement){
var myElement = document.getElementById(idOfAnElement);
myElement.getHeight: function (){
return this.style.height;
}
myElement.getWidth: function (){
return this.style.width;
}
return myElement;
}
Note: While it works, I wouldn't recommend it.
You need to take care not to overwrite existing methods/fields and if multiple libraries will take the same approach a collision is likely.
And this is NOT what jQuery is doing: they create a wrapper object. To get the element from jQuery you need to use [0] for example $('#myEl')[0].

Related

Using Prototype with "Namespace" for existing object

I am looking to achieve something along the following.
HTMLSpanElement.prototype.testNS = {
_this: this,
testFunc: function() {
console.log(this.innerHTML) //undefined as expected as this is the testFunc object
},
testFunc2: function() {
console.log(this._this) //Window object
}
}
My goal is to add some helper functions directly to a span element in this case.
So, if I had the following:
<span>test</span>
I could find the span and call this code to return "test"
spanElement.testNS.testFunc()
I know that a function retains scope of it's parent when I do it like so...
HTMLSpanElement.prototype.testFunc = function() {
console.log(this.innerHTML)
}
But I am attempting to organize the code a bit and make it more obvious where the functions are coming from when I add them, and I can't seem to find a way to retain scope, when I do a normal JSON object grab the this scope into _this: this it just returns the global scope of "window".
Disclaimer: You shouldn't be trying to modify the prototypes on built-in types, especially host objects. It's a bad idea.
The reason your approach isn't working for you is that the functions are being called with the testNS object as the this.
You can get this to work if you define testNS as a property with a getter function, using Object.defineProperty. The reason this works is that the get function runs in the context of the object on which the property is being accessed (which would be the span):
Object.defineProperty(HTMLSpanElement.prototype, 'testNS', {
get: function() {
var _this = this;
return {
testFunc: function() {
console.log(_this.innerHTML)
},
testFunc2: function() {
console.log(_this)
}
}
}
});
var span = document.getElementById('mySpan');
span.testNS.testFunc();
span.testNS.testFunc2();
<span id="mySpan">Wah-hoo!</span>
A more "vanilla" approach is to just have testNS be a plain function and call it like one. This works because testNS is called in the context of the object on which it is being called (again, the span):
HTMLSpanElement.prototype.testNS = function() {
var _this = this;
return {
testFunc: function() {
console.log(_this.innerHTML)
},
testFunc2: function() {
console.log(_this)
}
}
}
var span = document.getElementById('mySpan');
span.testNS().testFunc();
span.testNS().testFunc2();
<span id="mySpan">Wah-hoo!</span>
When you call a function as foo.bar() then this inside bar refers to foo. Hence if you call the function as spanElement.testNS.testFunc(), this refers to spanElement.testNS.
_this: this, cannot work because this cannot refer to a <span> element.
To get access to spanElement from testFunc you could implement testNS as a getter:
Object.defineProperty(HTMLSpanElement.prototype, 'testNS', {
get: function() {
var element = this;
return {
testFunc: function() {
console.log(element.innerHTML);
},
};
},
});
document.querySelector('span').testNS.testFunc();
<span>foo</span>
Because it's a strange requirement I wrote a an equivalent strange solution :-)
Basically the createElement has been overriden in order to add a namespace object literal and then define a new function testFunc on top of the namespace using the instance of the element binded to the function
!function(){
var defaultNamespace = "testNS";
var createElement = document.createElement;
document.createElement = function(tag, namespace) {
var element = createElement.apply(document, arguments);
element[namespace || defaultNamespace] = {
testFunc : function() {
console.log(this.innerHTML);
}.bind(element)
};
return element;
}
}();
var span = document.createElement("span");

How to define shorthand function in javascript

I'm wondering how to setup a shorthand function for a shorthand selector in javascript. I apologise if that isn't the correct termonolgy.
Example:
var abc = function (selector) {
return document.querySelector(selector);
};
Allows you to:
var temp = abc('#someID').value;
What I'm wondering is how do you go about creating a custom .something (in a similar fashion to how jQuery have .val)?
For example calling:
abc('#someID').doSomething;
The the doSomething command allowing you to update the value (or pull it back) in a similar fashion to .val etc.
Thank you in advance.
Well, this is a very nice JS code-design question.
Let's try to create a simple jQuery implementation. For this, we should first scope things up.
jQuery function is a wrapper. It will hold a reference to the node in the DOM, and it will provide an array functions that will "operate" on the node.
Most of the functions (setters, for being more specific) should return a pointer to the wrapper itself, so you can chain operations.
You can define the wapper first, by defining your function.
// Here we define the constructor.
var q = function(selector){
this._node = document.querySelector(selector);
// Add more private stuff here if you like
};
//Now we can add functionality to the function prototype.
q.prototype.hide = function(){
this._node.style.visibility = 'hidden';
return this;
};
q.prototype.show = function(){
this._node.style.visibility = 'visible';
return this;
};
q.prototype.val = function(){
return this._node.value;
};
q.prototype.click = function(callback){
this._node.onclick = callback;
return this;
};
// This is just for not having to call new every-time we want a new instance
var $q = function(selector){
return new q(selector);
};
Now let's play a bit
<label for="name"> Hey I'm a text box</label>
<input id="name" value="" />
<button id="clickMe"> Click me </button>
We will attach a click handler to the button, when the user clicks, we display the value that the textbox contains, then we hide the text box. All in a single line (chained commands).
$q('#clickMe').click(function(){
alert($q('#name').hide().val());
});
See JsFiddle https://jsfiddle.net/4Lfangj4/
To make that, you must return an object (easiest solution) or extend the prototype (advanced solution).
Returning an object
You can return the doSomething() method:
var abc = function (selector) {
return {
doSomething: function() {caller()},
dom: document.querySelector(selector);
}
};
And it works:
var temp = abc("#someID").dom.value;
var doSome = abc("#someID").doSomething();
Extending prototype
You can add a function to the object prototype:
var abc = function(sel){
return document.querySelector(sel);
}
abc.prototype.doSomething = function() {
caller();
};
And it works
var temp = new abc("#someID");
temp.doSomething(); //doSomething() method
temp.value; // value attribute of element
Jquery keeps your selection in an internal property and decorates that property with methods that can help with is DOM presence.
Almost every time it returns the same object so you can chain method calls.
The point is that you cannot avoid keeping a reference to the selected DOM element and the decoration part
A simple example about selection and manipulating the DOM element
note here i store a reference to document.querySelector and document.querySelectorAll which are pretty much as good as jquery selection mechanism (Sizzle)
var MyWrapper = (function(){
var $ = document.querySelector.bind(document);
var $$ = document.querySelectorAll.bind(document);
var slice = Array.prototype.slice;
var selection;
var that = {
select: select,
remove: remove,
html: html
};
function select(selector){
selection = $(selector);
return that;
}
function remove(){
selection.parentNode.removeChild(selection);
return undefined;
}
function html(htmlstring){
if(typeof htmlstring == 'undefined'){
return selection.innerHTML;
} else {
selection.innerHTML = htmlstring;
return that;
}
}
return that;
}())
of course jQuery is a much complex and sophisticated library for all kind of use cases but the above code can get you started

jQuery call plugin method from inside callback function

I am using a boilerplate plugin design which looks like this,
;(function ( $, window, document, undefined ) {
var pluginName = "test",
defaults = {};
function test( element, options ) {
this.init();
}
test.prototype = {
init: function() {}
}
$.fn.test = function(opt) {
// slice arguments to leave only arguments after function name
var args = Array.prototype.slice.call(arguments, 1);
return this.each(function() {
var item = $(this), instance = item.data('test');
if(!instance) {
// create plugin instance and save it in data
item.data('test', new test(this, opt));
} else {
// if instance already created call method
if(typeof opt === 'string') {
instance[opt].apply(instance, args);
}
}
});
};
})( jQuery, window, document );
Now say i have two <div> with same class container.
And now i would call my test plugin on these divs like so,
$(".container").test({
onSomething: function(){
}
});
Now when function onSomething is called from inside my plugin how can i call that plugin public methods referring to the instance onSomething function was called from?
For example something happened with the first container div and onSomething function was called for only first container div.
To make it a bit more clear I have tried to pass this instance to the onSomething function, that way i expose all plugin data and then i can do something like,
onSomething(instance){
instance.someMethod();
instance.init();
//or anything i want
}
To me me it looks quite wrong so there must be a better way... or not?
Well im not sure if it is the best idea, but you could pass the current object as a parameter. Let's say onSomething : function(obj) { }
So whenever "onSomething" is called by the plugin, you can call it like this: "onSomething(this)" and then refer to the object asobject`
Lets give a specific example.
var plugin = function (opts) {
this.onSomething = opts.onSomething;
this.staticProperty = 'HELLO WORLD';
this.init = function() {
//Whatever and lets pretend you want your callback right here.
this.onSomething(this);
}
}
var test = new Plugin({onSomething: function(object) { alert(object.staticProperty) });
test.init(); // Alerts HELLO WORLD
Hope this helps, tell me if its not clear enough.
Oh wait, thats what you did.

javascript is it possible to use a string to call a object function

I have a generic function which can speak to multiple other functions in appropriate objects is it possible to use a string to call the appropriate function.
var string = "save";
var generic = (new function (string) {
string."alert()";
return this;
})
var save = (new function (string) {
this.alert = (function () {
alert("your document has been saved")
return this
})
return this
})
var notSaved = (new function (string) {
this.alert = (function () {
alert("your document has not been saved")
return this
})
return this
})
I am using it for a far more complex set up but here is an example. Is this possible?
Sure you can. Try something like this:
window[string].alert();
Looking at your code it's hard to tell what you're actually trying to achieve. Nonetheless, here are a few ideas that may be relevant.
First, let's make a couple of objects:
var rabbit = {
name: 'Peter',
hop: function () {
return this.name + ' hopped!'
},
jump: function () {
return this.name + ' jumped!'
}
}
var hairy_maclary = {
name: 'Hairy Maclary',
jump: function () {
return this.name + ' jumped over the fence!'
}
}
Now, you could define a function which invokes the hop method on whichever object is passed to it:
function hop(object) {
return object.hop()
}
hop(rabbit) // 'Peter hopped!'
I'm not sure why you'd do this rather than invoking hop directly, but perhaps you want to do extra stuff before or afterwards.
If you wanted to you could create a completely generic function which would invoke a given method on a given object:
function invokeMethod(object, method) {
object[method]()
}
invokeMethod(hairy_maclary, 'jump') // 'Hairy Maclary jumped over the fence!'
This is a really strange thing to want to do, though. Perhaps you could provide more of an idea of what you're actually trying to do, since your example code is rather odd.
You can enclose your functions within some object so you can access by passing name of the property using some variable (in this case named string), eg. like that:
var string = 'notSaved';
var funcs = {};
funcs.save = new function(){
this.alert = function(){
alert('called save.alert()');
};
return this;
};
funcs.notSaved = new function(){
this.alert = function(){
alert('called notSaved.alert()');
};
return this;
};
funcs[string].alert();
See working example on jsfiddle.
If your variables are global (they should not), they are also automatically enclosed within window object, so you can call them also like that: window[string].alert(). This will not work for non-global functions (in this case my solution seems to be the only one not using eval()).
eval("alert('test');");
You can call functions with eval. Even you can declare functions.
eval("function test(){ alert("test");}");
test();

Javascript Callable and prototype extendable Function

Basically I looking for the ability to attach methods to an executable function while using the javascript prototype method. The code below demonstrates want I'm talking about and the functionality I'm looking for, but it is really a hack. Notice I have a valid this object to attach variables along with a main and init function.
function create(){
var $this = {},
main = function(){
prototype.main.apply($this,arguments);
};
prototype.init.apply($this,arguments);
//Add additional prototype methods by brute force, ugly
for(i in prototype)-function(i){
main[i]=function(){
prototype[i].apply($this,arguments);
}
}(i);
return main;
};
var prototype = {
//called when you create the object
init:function(text){
console.log('init');
this.text = text;
},
//called when you call the object
main:function(){
console.log('main');
console.log(this);
},
method:function(){
console.log(this.text);
}
};
//create returns a function that also has methods
//the below line will call the init method
var fun = create('some variables');
//call main function
fun();
//call methods
fun.method();
I'm afraid I might be missing something obvious.
Here is the same functionality as above, but instead extends the global function prototype.
Extending the global properties is bad practice, so I am looking for a alternative solution.
Function.prototype = {
//called when you create the object
init:function(text){
console.log('init');
this.text = text;
},
//called when you call the object
main:function(){
console.log('main');
console.log(this);
},
method:function(){
console.log(this.text);
}
};
function create(){
var ret = function(){
ret.main.call(main);
};
ret.init.apply(main,arguments);
return ret;
};
//create returns a function that also has methods
//the below line will call the init method
var fun = create('some variables');
//call main function
//fun();
//call methods
fun.method();
Just as an obvious point, it doesn't appear you can use the typical new object approach because if you call new you can't return a separate value.
Any explanation or considerations would be great!
You can put your the prototype functions into the "constructor" body. This technically is what you are currently doing, but defining them explicitly rather than using a helper method is much cleaner. Then, you can further simplify your code using the following pattern for public and private variables and methods:
function Fun(text) {
// This is the main function
var fn = function () {
return 'main';
};
// Attach public variables and methods
fn.publicVariable = 'public';
fn.publicMethod = function () {
return text; // text is a "private variable"
};
// Do whatever initialization
console.log('init');
// Return the main function
return fn;
}
var fun = Fun('this is some text'); // "init"
fun() // "main"
fun.publicMethod() // "this is some text"
console.log(fun.publicVariable); // "public"
console.log(fun.text); // undefined
By "the JavaScript prototype method", do you mean using the Function.prototype property to implement inheritance? Or are you just trying to create functions that have an initializer and attached methods?
Your example does the latter, so I'll assume that's what you you're looking for. Does this do what you're looking for?
function create(text)
{
var main = function()
{
console.log('main');
console.log(this);
}
var init = function()
{
console.log('init');
main.text = text;
}
main.method = function()
{
console.log(main.text);
}
init();
return main;
}
//the following line will call init
var fun = create('some variables');
//call main
fun();
//call methods
fun.method();

Categories

Resources