Method chaining in javascript - javascript

This working code is using Sproutcore:
person = SC.Object.create({
firstName: 'Foo',
lastName: 'Bar',
fullName: function() {
return this.get('firstName') + " " + this.get('lastName');
}.property()
});
console.log(person.get('fullName')); // "Foo Bar"
I wonder where property() is declared and how they have made this to work.
When I try to reconstruct this without the SC class, it gives me:
TypeError: Object function () {
return this.get('firstName') + " " + this.get('lastName');
} has no method 'property'
How does the code looks like to make it work?

Sproutcore is extending the function prototype.
Function.prototype.property = function() { /* code here */ };
The specific code use by sproutcore is at https://github.com/sproutcore/sproutcore/blob/master/frameworks/runtime/core.js#L908
SC.mixin(Function.prototype,
//...snip...
property: function() {
this.dependentKeys = SC.$A(arguments) ;
var guid = SC.guidFor(this) ;
this.cacheKey = "__cache__" + guid ;
this.lastSetValueKey = "__lastValue__" + guid ;
this.isProperty = YES ;
return this ;
},
//snip
);
In their case, they are using their own mixin method, but the concept is the same: extending the prototype

Presumably, Sproutcode has modified Function.prototype to include a property function.
You could just look at the source code.

Related

Can a function be declared as a variable in JavaScript?

Consider the following JavaScript object definition :
var person = {
firstName: "John",
lastName : "Doe",
id : 5566,
fullName : function() {
return this.firstName + " " + this.lastName;
}
};
I know that if we want to use the object property(i.e. a function) we have to write the following code :
person.fullName();
As per my knowledge, JavaScript objects are containers for named values called properties or methods.
Also, I know that I can define the object properties like firstName, lastName, id as individual variables.
Now, my question is can I also define the function "fullName" as a variable? If it is possible then how? and if not then why?
Thank You.
It is possible. Note that your code is equivalent to this code:
var person = {};
person.firstName = "John";
person.lastName = "Doe";
person.id = 5566;
person.fullName = function() {
return this.firstName + " " + this.lastName;
}
The important bit to see is that function() { return this.firstName + " " + this.lastName; } (or rather, the result of evaluation of that string of code) is a value, just like 5566 is, and can be contained in a property, or a variable, or an array... just like 5566 can. The only difference is, one is a number, the other - a function.
Besides the original example of a function stored in a property ("method"), here is an example of a functional value being stored in a variable:
var sayHello = function(name) { console.log("Hello, " + name); }
Here it is in an array:
var adders = [
function(x) { return a; },
function(x) { return (a + 1) % 3; }
function(x) { return (a + 2) % 3; }
];
Here it is being passed as a parameter:
function twice(f, x) {
return f(f(x));
}
twice(function(x) { return x * 2; }, 7);
// 28
Yes
Here is simple answer with example to your question
jQuery(document).ready(function() {
window.$ = jQuery;
initializeGlobelCalls.init();
});
var initializeGlobelCalls = function () {
var validatefunction = function() {
$(document).on('click','#divid',function(){//event trigger when you want to call function
//your function code
});
};
return {
init: function () {
validatefuction();//can add multiple functions here
}
};
}();
with this structure you can write multiple functions ,first need to define function like validatefunction and then add into init
It is not possible unless you generate fullName when creating the object such as the following:
var person = {
firstName: "John",
lastName : "Doe",
id : 5566,
fullName : ''
};
person.fullName = person.firstName + person.lastName;
Otherwise there's no way to create a static variable only one that will be created by the function when called (such as in your original example).
That is not possible because by the way JavaScript was designed, you can't have dynamic properties assigned statically (apart from ES6 getters as cited below, which will still generate the value on every call) in a way that they'll only be generated once automatically without some kind of algorithm from your part or a library to do that for you.
As I cited above, you can try ES6 getters but that will only make it look like a property, it will still get called every time it is accessed:
Example:
var person = {
firstName: "John",
lastName : "Doe",
id : 5566,
get fullName() { return this.firstName + ' ' + this.lastName; }
};
Then you'd access it like this: person.fullName
In JavaScript a variable can point to function as well.
Example:
var fullName = function(param) {
return param;
}
console. log(fullName('some text'));

Backbone class properties? 'this.property' won't work in it's methods?

Help with Backbone needed:
var Vehicles = Backbone.Model.extend({}, {
name: 'Sabre',
summary: function() {
console.log(this.name +" is a dog!");
}
});
Vehicles.summary();
This prints out: " is a dog"
Two questions:
Why doesn't it print out the name? Why doesn't this.name work?
On the following line, what is the difference between firstBlock and secondBlock?
Backbone.Model.extend({firstBlock},{SecondBlock});
If you look at this inside your summary static method:
summary: function() {
console.log(this);
}
you'll see something like this:
function (){return r.apply(this,arguments)}
so this is indeed the constructor function that you'd expect it to be. That means that this isn't the problem.
When you say M = Backbone.Model.extend(...), you get a constructor function back in M. But, JavaScript functions have non-writeable name properties:
Function.name
The function.name property returns the name of the function.
So the problem is that you're trying to use name as a static property but that property name is already taken and you cannot overwrite it.
If you use a different property name:
var Vehicles = Backbone.Model.extend({}, {
pancakes: 'Sabre',
summary: function() {
console.log(this.pancakes + " is a dog!");
}
});
then things will behave as expected because functions (usually) don't have non-writeable pancakes properties.
Demo: https://jsfiddle.net/ambiguous/qk78edkp/
As far as your first question goes, it does work but the constructor function that Backbone.Model.extend gives you doesn't have a name.
Pimmol's answer covers the second question well enough so I'll leave that alone.
From the annotated source:
var extend = function(protoProps, staticProps[..]
Which could be a bit confusing reading the docs:
http://backbonejs.org/#Model-extend
Backbone.Model.extend(properties, [classProperties])
But it means the same :)
The reason the output is 'is a dog' is because name and summary are static properties of the Vehicles model. So this won't work in the static summary method since it's not an instance you're refering to. You can access those properties without creating an instance.
So this would work:
var Vehicles = Backbone.Model.extend({}, {
foo: 'Sabre',
staticMethod: function () {
console.log(Vehicles.foo + " is a dog!");
}
});
Vehicles.staticMethod();
The first argument in the extend are the protoProps as seen in the annotated source. So if you want to use those properties, you have to create a new instance :
var Vehicles = Backbone.Model.extend({
name: 'Sabre',
summary: function() {
console.log(this.name + ' is a dog');
}
});
var v = new Vehicles();
v.summary();
And ofcourse you can combine those two:
var Vehicles = Backbone.Model.extend(
{
name: 'Sabre',
summary: function() {
console.log(Vehicles.bar + ' is a static property');
console.log(this.name + ' is NOT a static property');
}
},
{
bar: 'foo',
staticMethod: function() {
console.log(Vehicles.bar + ' is a static property');
}
}
);
var v = new Vehicles();
v.summary();
Vehicles.staticMethod();

How avoid getter/setter functions in the module pattern when passing arguments

For some time now, I've been structuring my JavaScript Code like this:
;(function() {
function Example(name, purpose) {
this.name = name;
this. purpose = purpose;
}
Example.prototype.getInfo = function() {
return 'The purpose of "' + this.name + '" is: ' + this.purpose;
}
Example.prototype.showInfo = function() {
alert(this.getInfo());
}
var ex = new Example('someModule', 'Showing some stuff.');
ex.showInfo();
})(undefined);
Fiddle
Now I've realized that this pattern is far from ideal as is has some problems:
It doesn't utilize closures/scope so simulate public & private
members.
It doesn't export something, meaning the module itself is not really encapsulated & namespaced.
(Disclaimer: I haven't used it in any bigger project, so I might be missing some important details that occur when working under real live conditions.)
To solve these issues, I started looking into JavaScript design patterns. One of patterns that immediately appealed to me is the module pattern.
I tried to rewrite the code above using the module pattern, but I can't get it quite right:
var Example = (function() {
function getInfo() {
return 'The purpose of "' + name + '" is: ';
}
// Public stuff
return {
name: '',
purpose: '',
setInfo: function(name, purpose) {
this.name = name;
this.purpose = purpose;
},
showInfo: function() {
alert(getInfo());
}
};
})(undefined);
Example.setInfo('someModule', 'Showing some stuff.');
Example.showInfo();
Non working Example: Fiddle
Now the module itself is encapsulated inside the Example namespace & there is something like public & private members, but working with it is quite different & difficult to me, probably because I can't wrap my head around the fact that there is no instance created using the new keyword.
In the non working example, why does it alert result although that string is never set & why is purpose not alerted? I think the setInfo method itself works, so it's probably a scope issue I don't understand.
Also, is there a way around using getter/setter functions? To me it currently looks like assignments I would normally do in the constructor aren't really possible using the module pattern:
function Example(name, purpose) {
this.name = name;
this. purpose = purpose;
}
Using the module pattern, I either have to user getter/setter or something like a 'universal setter function' in form of an init function.
Coming from PHP OOP, I always try to avoid them as much as possible, but I don't really know how to handle that in a prototype based language.
Maybe there is something similar to the module pattern, but with using prototypes – something like module & constructor pattern? It might be easier for me to understand.
Use it this way and it should work and you are right, this is scope issue.
Here is the working fiddle
Notice that I have taken snapshot of this in a variable and am using that. It is usually done in order to keep a reference to this when the context is changing.
No use of new Keyword
In your case returning {} is returning a new instance of anonymous object with properties as defined. Hence, you do not need new keyword also. You can take a look at this for anonymous objects.
When you use this, the scope of this changes in return {} object and they no more refer to the Example object.
Using getter / setter function
You don't need them. assignments would do, but remember, the variables would be attached with self so you would need to do self.name = name and self.purpose = purpose in order to do assignments or get values.
var Example = (function() {
var self = this;
function getInfo() {
return 'The purpose of "' + name + '" is: ' + purpose;
}
// Public stuff
return {
name: '',
purpose: '',
setInfo: function(name, purpose) {
self.name = name;
self.purpose = purpose;
},
showInfo: function() {
alert(getInfo());
}
};
})(undefined);
Example.setInfo('someModule', 'Showing some stuff.');
Example.showInfo();
Update:
Fiddle wasn't saved properly I have updated that. Also In there I just corrected your code.
I think this is what you are trying to achieve:
var Example = (function (params) {
var self = this;
self.name = params.name;
self.purpose = params.purpose;
function getInfo() {
return 'The purpose of "' + self.name + '" is: ' + self.purpose;
};
self.showInfo(alert(getInfo()));
return{
};
});
var myExample = new Example({
name: 'someModule',
purpose: 'somePurpose'
});
myExample.showInfo();
I'm not sure if that's what you're trying to achieve:
http://jsfiddle.net/Ly66mcxo/1/
Example = (function() {
var _name, _purpose;
function getInfo() {
return 'The purpose of "' + _name + '" is: ' + _purpose;
}
// Public stuff
return {
setInfo: function(name, purpose) {
_name = name;
_purpose = purpose;
},
showInfo: function() {
alert(getInfo());
}
};
})(undefined);
Example.setInfo('someModule', 'Showing some stuff.');
Example.showInfo();
Check now
var Example = (function () {
var _this = this;
_this.getInfo = function () {
return 'The purpose of "' + _this.name + '" is: ' + _this.purpose;
}
return {
setInfo: function (name, purpose) {
_this.name = name;
_this.purpose = purpose;
},
showInfo: function () {
alert(_this.getInfo());
}
};
})(undefined);
Example.setInfo('someModule', 'Showing some stuff.');
Example.showInfo();

Can you dynamically add local variables to a function?

I'm using objects to namespace my JavaScript code. These objects usually contain functions that are called mapping the this-pointer to the object itself using apply. However, I find it inconvenient to use the this-pointer everytime I want to access other functions or properties of the object, especially because in lots of cases I use the new-operator to use function-objects the way you would use classes. I would prefer writing new Line() instead if new this.Line().
It would be great if you could add local variables to a function the way php does it with extract (pseudocode following, it's a little more complicated)
var sample_object = {
"some_function": function() {}
}
test() {
extract(sample_object);
some_function(); // imported from sample_object
}
Is that even possible?
I'm pretty sure eval is your only answer; but you need to be aware that if there's any input outside of your control involved, it isn't safe
function dynamicArgs (varName, varValue) {
eval("var " + varName + "=" + JSON.encode(varValue) );
alert(a);
}
dynamicArgs("a", "value");
You can see the problem with this. How is your function supposed to call the dynamic variable if it doesn't know its name? I hardcoded it to the a variable since I pass it in when calling it, but that's not a good solution. The only solution would be another eval. You really should think about what you need to do and whether this is useful. But it's doable.
Here it is in action: http://jsfiddle.net/mendesjuan/GG3Wu/
function dynamicArgs (varName, varValue) {
eval('var ' + varName + "='" + varValue + "';");
alert(eval(varName));
}
dynamicArgs("f", "Here I am");
Now here's an example like what you're doing, creating a variable from this.MyConstructor
http://jsfiddle.net/mendesjuan/AK3WD/
var ns = {
MyConstructor: function(val) {
this.prop = val;
},
runConstructor: function(val) {
var Ctor = "MyConstructor";
eval('var ' + Ctor + ' = this.' + Ctor);
return new MyConstructor(val);
}
}
alert( ns.runConstructor("Hello").prop );
And here's an example if you wanted to import all the values from an object into the scope;
http://jsfiddle.net/mendesjuan/AK3WD/1/
var ns = {
MyConstructor: function(val) {
this.val= val;
},
anotherProperty: 5,
runConstructor: function(val) {
// Bring all the variables from this into this scope
for (var prop in this) {
eval('var ' + prop + ' = this.' + prop);
}
alert('Testing var anotherProperty: ' + anotherProperty);
var obj = new MyConstructor(val);
alert('Created MyConstructor: its prop is ' + obj.val)
}
}
ns.runConstructor("Hello");
There is controversial with, which has some great applications, but is marginally slow and prone to errors. It throws an error in the strict mode (which you should always opt into) and is going to be deprecated.
var sampleObject = {
someFunction: function() {},
b: 10
}
with (sampleObject) {
typeof someFunction // "function"
var a = 42
var b = 20
}
sampleObject.a // undefined
sampleObject.b // 20
Note, that new variables defined in a with-block won't be added to the object. Nevertheless, if the object already had an eponymous property in it, this property would be modified (thanks, #Rocket).
Just for fun, here's an implementation of extract using eval (which is even more evil than with). You can do unspeakable things with it, for example if your object has properties like sampleObject['x; while (true) { alert("Hi!") }'].
This is how I did it:
function smObject ( object) {
return function () {
function getter(prop) {
return function() {
return this[prop];
}
}
function setter(prop) {
return function(data) {
this[prop]=data;
}
}
for (var o = 0; o < object.length; o++) {
this[object[o]] = {};
this['get' + object[o]] = getter(object[o]);
this['set' + object[o]] = setter(object[o]);
}
}
}
now you can instantiate a function like this:
var fields = ['Name', 'Id', 'Other', '....' ]
var MyFunction = smObject( fields );
var myObject = new MyFunction();
// getter/setters
myObject.setId(5);
myObject.getId(); // will return 5
Regards,
Emanouil

How to define a getter property, for an already defined JavaScript object?

Consider this code:
// Creating an empty object, without inheriting (binding) to any prototype
var human = Object.create(null);
human.firstName = 'Saeed';
human.lastName = 'Neamati';
Now, I want to add a fullName property to this object, which returns the firstName + ' ' + lastName of the object.
Using object literal notation, I can simply write a getter function this way:
var human = {
firstName: 'Saeed',
lastName: 'Neamati',
get fullName() {
return this.firstName + ' ' + this.lastName;
}
}
But I can't figure out how to attach a getter property to an object, which is already built somewhere else.
You can use Object.defineProperty
Object.defineProperty(<object>, <property-name>, <descriptor>);
Where <descriptor> can be something like:
// from the example:
{ value: 0x9f91102,
get: function() { return 0xdeadbeef; } }
try this :
Human = function(){
human.firstName = 'Saeed';
human.lastName = 'Neamati';
};
human.prototype.getFullName = function(){
return this.firstName + ' ' + this.lastName;
}
var humanOne = new Human();
alert(humanOne.getFullName());
Hope it helps :)

Categories

Resources