I am creating a new object variable and passing an object as an argument:
var obj = new test({
first : $('#fname').val(),
last : $('#lname').val(),
fn : function() {
alert(this.first + " " + this.last);
}
});
This is the called function when creating the above variable:
var test = function(obj) {
this.fn = function() {
alert("No custom function was made.");
}
this.first = obj.first;
this.last = obj.last;
if(obj.fn)
this.fn = obj.fn(); //I also tried it without the '()' after 'obj.fn'
};
The first and last variables are fine, but I cannot figure out how to get the custom function that is passed to be set.
You mentioned that you tried removing the '()' after 'obj.fn'... seems to work when I do that. Here's the link to verify: http://jsfiddle.net/TD93x/3/
it worked for me
var test = function(obj) {
this.fn = function() {
alert("No custom function was made.");
}
this.first = obj.first;
this.last = obj.last;
if(obj.fn)
this.fn = obj.fn;
};
Related
I have the following JS code, how could I insert new function without adding inside the self object?
Function select(selector){
Var self = {
Print: ()=>{},
Delete: ()=>{}
};
Return self;
}
//I want to add new function here so I can call it by using select("something").newFunc()
Is there any ways to do that? I tried something as below, but I'm wondering if there's another way to do it.
After several hours of testing, I tried to assign all the methods inside a variable prototype's method (A), and then set A's prototype back to the variable's prototype. Then I can call it using the variable.
var myScript = function(selector){
return new myScript.prototype.init(selector);
}
var init = myScript.prototype.init = function(selector){
var self = {
//codes
};
return self;
}
init.prototype = myScript.prototype;
(function(mS){
mS.prototype.newFunc = function(){
return "Coding is Fun";
}
})(myScript);
After that, I can use myScript("something").newFunc()
That's what I've tried, please share if you know another way, thanks.
Constructor functions do not require the 'self' object you designed. In your case
You return the self object from the constructor
You use arrow functions that do not change the value of this. Arrow functions are cool, but they are not interchangeable with regular functions (at least not in every case - and inside a constructor function is such a case)
Look at the two constructor functions below (Select1 is based on your code, Select2 is based on a "how to do it"):
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype
// adding a self object - arrow functions
function Select1(selector) {
this.selector = selector
var self = {
print: () => {
return 'Select1 print: ' + this.selector
},
delete: () => {
return 'Select1 delete: ' + this.selector
}
}
return self
}
// no self object - regular functions
function Select2(selector) {
this.selector = selector
this.print = function() {
return 'Select2 print: ' + this.selector
}
this.delete = function() {
return 'Select2 delete: ' + this.selector
}
return this
}
// instantiating the two different Objects
let select1 = new Select1('selector1')
let select2 = new Select2('selector2')
// calling the print method on both Objects
console.log(select1.print())
console.log(select2.print())
// logging both objects
console.log(select1)
console.log(select2)
// modifying the prototype of the constructor functions
// modifying Select1.self's prototype would throw an error
/*Select1.prototype.self.newFunc = () => {
return 'Select1 newFunc: ' + this.selector
}*/
Select1.prototype.newFunc = function() {
return 'Select1 newFunc: ' + this.selector
}
Select2.prototype.newFunc = function() {
return 'Select2 newFunc: ' + this.selector
}
// logging the new function
// logging select1.newFunc() would throw an error, as you return 'self', that's not modified
// console.log(select1.newFunc())
console.log(select2.newFunc())
// logging the modified object
console.log(select1)
console.log(select2)
BUT
You should use correct indentation - code is much more readable that way
You should follow naming and casing conventions, so others can quickly see what is what in your code (constructor functions begin with a capital letter, but other reserved words do not (so casing is important too)
USAGE
And if you want to use it like myScript('selector').myFunc(), then you need to wrap it in another function (like you did in your second code sample):
function Select2(selector) {
this.selector = selector
this.print = function() {
return 'Select2 print: ' + this.selector
}
this.delete = function() {
return 'Select2 delete: ' + this.selector
}
return this
}
function myFunc(selector) {
return new Select2(selector)
}
console.log(myFunc('s1').print())
console.log(myFunc('s2').print())
If you want to be able to set the selector, then you need a set() function:
function Select2(selector) {
this.selector = selector
this.print = function() {
return 'Select2 print: ' + this.selector
}
this.delete = function() {
return 'Select2 delete: ' + this.selector
}
// this.setSelector is the set() function
this.setSelector = function(s) {
this.selector = s
}
return this
}
function myFunc(selector) {
return new Select2(selector)
}
// instantiating Select2
const selector2 = myFunc('s1')
console.log(selector2.print()) // expected: s1
// setting the 'selector' of the instantiated
// Select2 Object to a new value
selector2.setSelector('s2')
console.log(selector2.print()) // expected: s2
I'm watching a course on JS design patters and in one of the examples there is this code:
var Task = function (name) {
this.name = name;
this.completed = false;
}
Task.prototype.save = function () {
console.log('saving Task: ' + this.name);
};
var UrgentTask = function (name, priority) {
Task.call(this, name);
this.priority = priority;
};
UrgentTask.prototype = Object.create(Task.prototype);
UrgentTask.prototype.save = function () {
console.log('do special stuff before saving');
//why use Task.prototype.save and not Task.save directly.
Task.prototype.save.call(this);
};
var ut = new UrgentTask('This is urgent', 1);
ut.save();
My question is why inside the UrgentTask.prototype.save function do i have to use Task.prototype.save and not Task.save directly with the .call() method?
and why if i use Task.save it returns can't read property 'call' of undefined??
I need to know who call a function, for example i have code like this :
var observe = function(newvalue, callback) {
console.log('who call me?');
callback('new value is ' + newvalue);
}
var ViewModel = function() {
var self = this;
self.Id = '1';
self.Name = observe;
self.NickName = observe;
self.someFunction = function() {
return 1 + 2;
}
}
var vm = new ViewModel();
vm.NickName('test', function(resp) {
console.log(resp);
})
For this example, in observe i need the code know who call it is vm.NickName or NickName.
How to trick this problem with pure javascript?
From within a function, you cannot determine what reference was used to call it. If you want to do that, you need to create separate functions (which can then call the central one), or pass it an argument that tells it how it's being called, etc.
For instance, this example passes it an argument:
var observe = function(who, newvalue, callback) {
console.log('Called by: ' + who);
callback('new value is ' + newvalue);
};
// ...
self.Name = observe.bind(self, 'Name');
self.NickName = observe.bind(self, 'NickName');
I have a Object based on some closure, and want to implement event scheme here:
var class1 = function(val1)
{
var val = val1;
//------ want to call a method of Object of class1--------
var self = this;
setTimeout(function()
{
self.onEvent();
}, 1000);
//----------------
return {
f1: function()
{
return val;
},
onEvent: function()
{
console.log('not implemented yet. Override');
}
};
};
var obj1 = class1(5);
console.log(obj1.f1()); //5
obj1.onEvent(); //not implemented yet. Override
obj1.onEvent = function()
{
console.log('event fired');
}
got error, and I know the reason, and I need a solution:
5
not implemented yet. Override
/....../app.js:9
self.onEvent();
^
TypeError: Object #<Object> has no method 'onEvent'
It is possible if this bind with addEventListener scheme like this:
(The idea based on
Implementing events in my own object
)
var class2 = function()
{
var _this = this;
_this.events = {};
var fireEvent = function(name, args)
{
if (!_this.events.hasOwnProperty(name)) return;
if (!args || !args.length) args = [];
var evs = _this.events[name];
var l = evs.length;
for (var i = 0; i < l; i++)
{
evs[i].apply(null, args);
}
};
setTimeout(function()
{
fireEvent('testEvent', ['hello'])
}, 1000);
return {
addEventListener: function(name, handler)
{
if (_this.events.hasOwnProperty(name))
_this.events[name].push(handler);
else
_this.events[name] = [handler];
}
};
};
var obj2 = class2();
obj2.addEventListener('testEvent',
function(data)
{
console.log('event fired: ' + data);
});
event fired: hello
However, I prefer not to use addEventListener but .onEvent() scheme.
Is it possible? Perhaps it is possible using call/apply.
Thanks for your advice.
In your first block of code, you are returning an object, which is different from this or self.
You don't necessarily have to return this in your constructors but you should assign your functions on the returned object. If you create a variable for the object you want to return, you can use it in your setTimeout callback like so:
var class1 = function(val1)
{
var val = val1;
var obj = {
f1: function()
{
return val;
},
onEvent: function()
{
console.log('not implemented yet. Override');
}
};
setTimeout(function()
{
obj.onEvent();
}, 1000);
return obj;
};
For extra style points, you might want to capitalize the name of your constructors (and perhaps use new to instantiate them to make things clearer to your readers).
I'm trying to create something similar to static languages "static field". Basically: counter property should be incremented every time the init function is called, but no matter on which instance. This is a sample code I'm using to test ( http://jsfiddle.net/HK8BY/2/ ) :
var Widget = {
counter: 0,
init: function () {
this.counter++;
console.log("init called: " + this.counter);
}
};
var t1 = Object.create(Widget);
var t2 = Object.create(Widget);
t1.init(); // should print: init called 1
t2.init(); // should print: init called 2
console.log(t1);
console.log(t2);
Currently when I console.log instanes, I see that both proto and instance contain counter property. I thought that with this approach, only proto will have it.
So how can I change it to have only counter in prototype?
var twitter = (function() {
var counter = 0;
return {
init : function() { counter++; console.log("init called: " + counter); }
};
}());
var t1 = Object.create(twitter);
var t2 = Object.create(twitter);
t1.init();
t2.init();
http://jsfiddle.net/HK8BY/1/
So you just create IEFE (Immediately executed function expression) that returns the desired object. The counter variable is available to the closure of that object's init function.
var Widget = {
init: function () {
this.prototype.counter++;
console.log("init called: " + this.counter);
}
};
Widget.prototype.counter = 0;
var t1 = Object.create(Widget);
var t2 = Object.create(Widget);
t1.init();
t2.init();
console.log(t1);
console.log(t2);
You can simulate static fields by defining properties on a constructor function, but if you prefer to use Object.create in place of new then this might not be a solution you want to consider.
function Widget() {
this.init()
};
Widget.counter = 0;
Widget.prototype.init = function() {
this.constructor.counter++;
console.log("init called: " + this.constructor.counter);
};