JavaScript Object Reference - javascript

I've seen many questions for that context, but I still can't figure out, what exactly my Problem is. (I'm still experimenting with JavaScript, especially with objects)
Code:
function Field(val)
{ var value = val;
this.__defineGetter__("value", function(){ return value; });
this.__defineSetter__("value", function(val){ value = val; if(this.onchange) this.onchange.call(); });
}
function LW_makePlan()
{
/* [...] */
this.Filter1=new Field("");
this.Filter2=new Field("");
this.Filter3=new Field("");
this.init = function()
{
/* [...] */
this.Filter1.onchange=this.getSomething;
}
this.getSomething = function()
{
arg="modus=doWhat";
arg=arg+"&filter1=" + this.Filter1.value;
arg=arg+"&filter2=" + this.Filter2.value;
arg=arg+"&filter3=" + this.Filter3.value;
request_fkt(null, true, arg , this.setSomething);
}
this.setSomething = function(data)
{
alert(data);
}
this.init();
};
What I'm trying:
test = new LW_makePlan();
test.Filter1.value="anything";
test.Filter1 has an "onchange"-property, that is checked in the setter of "Field". if set, the setter will also call the object given within the onchange-property.
this works so far BUT it seems, that this call creates a whole new object-instance ... no not an instance, it is, as if the function "getSomething" is copied as a stand-alone function, because the Code i called, but for example this.Filter1 within the function "getSomething" is undefined ...
Why is this happening and how can I avoid this?
PS: I don't want to use some type of event-handling-Things from 3rd Party codes, I'd like to do it myself with a little help maybe.
EDIT:
Thanks to Steffen Heil, changed to:
var scope=this;
this.Filter1.onchange=function() { scope.getSomething(); };
and it works!

Your call to this.onchange is in Field, so you are calling a function of Field. The assignment this.Filter1.onchanged=this.getSomething kind of copies the method getSomething from LW_makePlan to Field, where it will be called.
So inside of getSomething that is now called onchanged the reference this referes to the Field not the LW_makePlan.
Replace the assignment with this:
var source = this;
this.Filter1.onchange = function() { return source.getSomething(); };
And it will work. Most frameworks have a bindmethod that makes this more readable (hiding the extra variable in a scope).
In reply to the first comment:
You can explicitly call a function like this:
x.call( object, arg1, arg2, ag3 );
x.apply( object, [ arg1, arg2, arg3 ] );
These the are the same and it does not matter what x is. Inside the called function this has the value of object.
x can be:
alert
window.alert
(function(){})
(alert)
(window.alert)
Normal calls to a function are shortcuts:
object.f = g;
object.f( arg1 ) => g.call( object, arg1 );
f( arg1 ) => f.call( window, arg1 );
While window is the global object in a browser; other environments may use another global object.
While the difference between these two shortcuts seems tivial, what about the following?
(object.f)( arg1 )
This is completely valid javascript, as object.f is a function and a function can be invoked using (args1). But:
object.f = g;
(object.f)( arg1 ) => g.call( window, arg1 )
So a.f = b.f; copies a member reference from a to b, but the this context, the code is executon on depends on the way f is called.
a.f(x) == a.f.call(a,x) == (a.f).call(a,x) == b.f.call(a,x) == (b.f).call(a,x)
b.f(x) == b.f.call(b,x) == (b.f).call(b,x) == a.f.call(b,x) == (a.f).call(b,x)
By the way, you can define your own bind very easily:
function bind( object, method ) {
return function() {
return object[ method ].apply( object, arguments );
};
}
Then the original code would become:
this.Filter1.onchange = bind( this, 'getSomething' );
This would match the fix I gave above using "late binding". Most libraries prefer "early binding":
function bind( object, method ) {
return function() {
return method.apply( object, arguments );
};
}
Then the original code would become:
this.Filter1.onchange = bind( this, this.getSomething );
The advantage is better performance, but the main difference is what happens, when getSomething changes after bind was called. The first implementation calls the new value, the second the old value.

Related

Why pass an undefined javascript function parameter?

So I'm learning Javascript and I see this code:
var apple = {//... an object with some properties};
var fruit = apple.someMethod(function (b) {return b.a_property_of_apple});
Where someMethod and a_property_of_apple are valid methods and properties.
My question pertains to the argument, b, of the anonymous function which is not declared or defined anywhere else:
function (b) {return ...
What is going on here? What is b and why is it being used?
Apologies in advance for the basic nature of the question. If someone just wants to drop some focused terms on me to read up on that would be great short of an explanation.
The anonymous function is a callback function being passed to the apple.method() invocation.
apple.method() will invoke that anonymous function at some point during it's execution, ( or pass it to another function ). Whenever it's invoked it will be invoked with an argument that will be available inside the callback. You could call it b, or response, or whatever you want (logical names are best) and be able to use it within the anonymous function.
You should read about Callback functions over at MDN.
EDIT: I will explain the parts to you
var apple = {} This is the definition of an object
var fruit = apple.someMethod(function (b) {return b.a_property_of_apple}); is defining that fruit is equal to the return value of the invocation of apple.someMethod(...)
apple.someMethod(function (b) {return b.a_property_of_apple}); is the invocation of apple.someMethod with function (b) {return b.a_property_of_apple} as the only argument.
The b argument in the anonymous function function (b) {return b.a_property_of_apple} will be passed to it's invocation within the apple.someMethod.
Here is an example snippet.
// define apple
var apple = {
// define method
someMethod: function( callback ) {
var obj = {
a_property_of_apple: "Eat me!" // this will be returned
}
// return the invocation of callback with obj as argument
return callback(obj);
}
}
var fruit = apple.someMethod(function (b) {return b.a_property_of_apple});
console.log(fruit);
EDIT: Ok, going to use something slightly less abstract as an example.
// notice employees being passed to this function
// that is called an argument and is usable inside the function
var orginization = function( employees ) {
// this will take the empoyees argument and assign it to this.employees
// or set this.employees to an empty array if there is no employees argument
this.employees = employees || [ ];
// this is a method ( a method is a function on an object )
// this function takes 3 arguments
this.addEmployee = function( employee ) {
// we use the 3 arguments to push a new object with title, name, and salary
// properties provided by the function arguments
this.employees.push( employee );
}
// this method returns the value stored in this.employees
this.getEmployees = function() {
return this.employees;
}
}
// this is a variable an array of employees only containing 1 employee
// i will use it in the creation of my new orginization
var employess = [
{
title: "CEO",
name: "Enola",
salary: "$$$$$$$"
}
];
// i use the new to create learningInc from originization( employees )
// originization is a constructor function which creates an object
// with methods and properties found on the constructor
var learningInc = new orginization( employess );
// console.log learningInc.getEmployees() an you will see still only the CEO
// works here
console.log( "before newHire: ", learningInc.getEmployees() );
// lets make a newHire
var newHire = {
title: "Peon",
name: "Sadly McFrownFace",
salary: "$"
};
// add the newHire to the employess of learningInc wth out getEmployees() method
learningInc.addEmployee( newHire );
// log the new value of learningInc.getEmployees and you see we now have 2 employees
console.log( "after newHire: ", learningInc.getEmployees() );
Ok now notice this line var learningInc = new orginization( employess );
The employees variable I'm passing to this function as an argument is used in this function var orginization = function( employees ) { ... }.
Hope this help.
My question pertains to the parameter, b, of the anonymous function which is not declared or defined anywhere else: What is going on here?
What is b and why is it being used?
Why you say it is not declared? It is declared right there. Consider this simple JavaScript function:
function doSomething(a, b){
//do something here;
}
In this code, we are creating a function, naming it "doSomething", and declaring two parameters for it a and b. This is how we declare function parameters in JavaScript. Now your example:
function (b) {return ...
is exactly the same, except we didn't give this function a name, which means it is an anonymous function. That's the only difference, but its parameter b is declared right there like any standard function. So there is nothing special going here, it's a standard function parameter and used as such.
There are a couple concepts at work here
Function declarations vs function expressions; you can use function as an operator to define a function, and assign the function to an identifier and pass it around like any normal object
Callbacks; you can pass a function CB into another function A to be called by A (as defined by A)
Passing something without an identifier
Function Declaration
// declare function
function foo(argFoo) {
console.log('foo', argFoo);
}
// invoke function
foo('was declared'); // "foo" "was declared"
Function Expression
// express function
var bar = function (argBar) {
console.log('bar', argBar);
};
// invoke function
bar('was expressed'); // "bar" "was expressed"
Callbacks
function fizz(callback) {
console.log('first I fizz');
callback();
}
function buzz() {
console.log('then I buzz');
}
fizz(buzz);
// "first I fizz"
// "then I buzz"
Passing without an Identifier,
Basically, defining things in-place
// say we have some fn fizzbuzz
function fizzbuzz(foo) {
console.log(foo);
}
// we could pre-define what we want to pass to it
var i = 1;
fizzbuzz(i); // 1
// or we could pass directly
fizzbuzz(1); // 1
// with anything we like
fizzbuzz({some: 'object'}); // {some: "object"}
// even a function
fizzbuzz(function () {}); // function () {}
Maybe if I break down what is happening into more readable code, you can see what is happening.
someMethod is a method that take a function as an argument. This is more easily seen when broken down like below.
It's up to someMethod to determine what they do with that function. In this example, I am executing the function being passed into someMethod and passing it my this context.
var apple = {
name: 'Apple',
someMethod: function(func) {
return func(this);
}
};
function getName (b) {
return b.name;
};
const name = apple.someMethod(getName); // Apple
To your question: b is defined as the first argument to your anonymous function. This is more clearly expressed when the code is broken out above. But you could also express it like this:
const name = apple.someMethod(function(x) { return x.name; }); // Apple
or like this using ES6:
const name = apple.someMethod(x => x.name); // Apple

You don't know JS book - Soft Binding

I'm currently reading You don't know JS. In it, there is a section that talks about soft binding technique. Basically it's a variation of binding a function to a particular scope/context.
From the book:
It would be nice if there was a way to provide a different default for default binding (not global or undefined), while still leaving the function able to be manually this bound via implicit binding or explicit binding techniques.
if (!Function.prototype.softBind) {
Function.prototype.softBind = function(obj) {
var fn = this,
curried = [].slice.call( arguments, 1 ),
bound = function bound() {
return fn.apply(
(!this ||
(typeof window !== "undefined" &&
this === window) ||
(typeof global !== "undefined" &&
this === global)
) ? obj : this,
curried.concat.apply( curried, arguments )
);
};
bound.prototype = Object.create( fn.prototype );
return bound;
};
}
Generally I understand what the function does except this part:
bound.prototype = Object.create( fn.prototype );
Why do we have to setup a prototype when using this "soft bind" technique?
Why do we have to setup a prototype when using this "soft bind" technique?
It's more for completeness sake than anything else. If someone tries to create a new instance of the soft-bound function, they'd expect the resulting object to [[Prototype]] link to the same object as the original function's .prototype pointed. So, we make sure to set bound.prototype equal to reference that same object.
The chances of someone wanting to call new on a soft-bound function are low, I'd think, but just to be more safe, it's included nonetheless. The same, btw, is true of the polyfill for the built in bind(..) as listed here:
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_objects/Function/bind#Polyfill
From that page:
Why is new being able to override hard binding useful?
The primary reason for this behavior is to create a function (that can
be used with new for constructing objects) that essentially ignores
the this hard binding but which presets some or all of the function's
arguments. One of the capabilities of bind(..) is that any arguments
passed after the first this binding argument are defaulted as standard
arguments to the underlying function (technically called "partial
application", which is a subset of "currying").
I guess for the softbind to have the same benefits (to provide a constructor that has default arguments passed to it) you have to set the prototype as well or you're missing prototype functions when you use the bound function as a constructor:
//softBind code removed
function Test(arg1,arg2){
this.arg1=arg1;
this.arg2=arg2;
}
Test.prototype.sayArgs=function(){
console.log('args:',this.arg1,this.arg2);
}
//the binding part doesn't do anything so can pass null
var BoundTest = Test.softBind(null, 'arg1');
var bt = new BoundTest('arg2');
bt.sayArgs();//=args:arg1 arg2
If you are going to use it this way though you don't have to add softBind to the Function.prototype, you can use normal bind, either native or the MDN polyfill.
Note that with the polyfill you cannot pass a falsy argument as the first parameter to bind or it'll break.
//Using the MDN bind polyfill you can't pass any falsy
// value like null, undefined,"",0 and false
var BoundTest = Test.bind({}, 'arg1');
var bt = new BoundTest('arg2');
bt.sayArgs();//=args:arg1 arg2;
In the article, the example given is actually broken:
var bar = foo.bind( null, "p1" );
var baz = new bar( "p2" );
Should be:
var bar = foo.bind('anything non falsy' , "p1" );
[update]
//removed if, so it'll set softbind every time
Function.prototype.softBind = function(obj) {
var fn = this,
curried = [].slice.call( arguments, 1 ),
bound = function bound() {
return fn.apply(
(!this ||
(typeof window !== "undefined" &&
this === window) ||
(typeof global !== "undefined" &&
this === global)
) ? obj : this,
curried.concat.apply( curried, arguments )
);
};
bound.prototype = Object.create( fn.prototype );
return bound;
};
function Test(){
//this has the right prototype and has
// the default arguments
console.log('this is:', this,'arguments',arguments);
this.name='test';
}
Test.prototype.something=22
var BoundTest = Test.softBind(null,'arg1','arg2');
var bt = new BoundTest();
//bt is same as new Test('arg1','arg2') would be
console.log('bt is:',bt);
//this.name did not affect window
console.log(window.name);//not test
console.log(bt instanceof Test);//true

Custom Function class

I'm working on a project that involves constructing functions from other functions. I had the idea of writing a class to simplify things but I haven't been able to get it to work without resorting to using __proto__.
Here's basically what my vision is.
function MyFunction () {
// ...
}
var myFn = new MyFunction();
myFn(); // executes without error
myFn instanceof MyFunction; // returns true
The following code does just that using __proto__
function MyFunction () {
var fn = function () { return 'hello'; };
fn.__proto__ = this;
return fn;
}
var myFn = new MyFunction();
alert( myFn() ); // hello
alert( myFn instanceof MyFunction ); // true
Here's something I've tried using valueOf
function MyFunction () {
this.fn = function () { return 'hello'; };
this.valueOf = function () { return this.fn; };
}
var myFn = new MyFunction();
alert( myFn instanceof MyFunction ); // true
alert( myFn.valueOf()() ); // hello
alert( myFn() ); // error
And here's something else extending the function to contain all the properties of MyFunction.
function MyFunction () {
this.foo = 'hello'
var fn = function () { return 'hello'; };
for ( var i in this ) {
fn[ i ] = this[ i ];
}
return fn;
}
var myFn = new MyFunction();
alert( myFn() ); // hello
alert( myFn.foo ); // hello
alert( myFn instanceof MyFunction ); // false
I don't want to use __proto__ because it's non-standard. Also, this was kind of a freak idea, I'd really like to get it to work, but if it's not possible I'll live. But I guess my question is, is what I'd like to do possible?
Fascinating idea. I don't believe you can do it with standard ECMAScript yet, not even using ES5.
ES5 gives us better access to and control over the prototype, including providing a means of setting the prototype when creating objects (without having to go through constructor functions) with Object.create, but you can't construct functions via that mechanism. And that's what you would have to do, because instanceof uses the abstract spec [[HasInstance]] method, which is currently only implemented by functions, and the function implementation of it works by seeing if the object's underyling prototype ([[Proto]]) is === to the function's prototype property. The only standard way to set the object's underlying prototype is to create it via new MyFunction or via Object.create, and neither mechanism creates a function object.
ES.next may make this possible. There's a proposal that's been promoted to "harmony" status (so, fairly advanced) for a "set prototype operator", <|, which is intended to solve many of the problems currently solved via __proto__. One of the things it's for is "Setting the prototype of a function to something other than Function.prototype". Using it (in its current form), your MyFunction would look something like this:
function MyFunction () {
return MyFunction.prototype <| function () { return 'hello'; };
}
MyFunction.prototype = Object.create(Function.prototype);
That last bit is to make it that MyFunction.prototype is an object with the prototype Function.prototype, so that functions constructed via MyFunction have call, apply, bind, etc.

How does jQuery hijack "this"?

I'm just curious to know how jQuery is able to hijack the 'this' keyword in Javascript. From the book I'm reading: "Javascript the Definitive Guide" it states that "this" is a keyword and you cannot alter it like you can with an identifier.
Now, say you are in your own object constructor and you make a call to some jQuery code, how is it able to hijack this from you?
function MyObject(){
// At this point "this" is referring to this object
$("div").each(function(){
// Now this refers to the currently matched div
});
}
My only guess would be that since you are providing a callback to the jQuery each() function, you are now working with a closure that has the jQuery scope chain, and not your own object's scope chain. Is this on the right track?
thanks
You can change the context of a function (i.e. the this value) by calling it with .call() or .apply() and passing your intended context as the first argument.
E.g.
function fn() {
return this.foo;
}
fn.call({foo:123}); // => 123
Note: passing null to either call or apply makes the context the global object, or, in most cases, window.
It's probably worth noting the difference between .apply() and .call(). The former allows you to pass a bunch of arguments to the function it's being applied to as an array, while the latter lets you just add them as regular arguments after the context argument:
someFunction.apply( thisObject, [1,2,3] );
someFunction.call( thisObject, 1, 2, 3 );
From the jQuery source:
for ( var value = object[0];
i < length &&
callback.call( value, i, value ) // <=== LOOK!
!== false;
value = object[++i] ) {}
It doesn't hijack anything - it just makes sure that "this" is pointing at what it wants it to. Look up the standard "call" function that's available for any Javascript function object.
See the documentation for Function.apply. The first parameter is the "context". It can be any object. If null, it will be scoped globally.
The function type in JavaScript has a method called apply() which allows you to specify to what object this is bound at. Its signature is:
apply(thisObj, arguments);
Once called, it calls the function binding this to thisObj and passing the arguments arguments.
It is usually used as such:
function product(name, value)
{
this.name = name;
if (value > 1000)
this.value = 999;
else
this.value = value;
}
function prod_dept(name, value, dept)
{
this.dept = dept;
product.apply(this, arguments);
}
prod_dept.prototype = new product();
// since 5 is less than 1000 value is set
var cheese = new prod_dept("feta", 5, "food");
// since 5000 is above 1000, value will be 999
var car = new prod_dept("honda", 5000, "auto");
try this:
var MyObject = { "Test": "Hello world!" };
(function ()
{
alert(this.Test); // Gives "Hello world!"
}).call(MyObject);
(function ()
{
alert(this.Test); // Gives "Hello world!"
}).apply(MyObject);
(function ()
{
alert(this.Test); // Gives "undefined"
})()
function.apply() and function.call() allow you to change what this points to in Javascript. Here's a couple of handy articles that explain it in greater detail - Scope In Javascript and Binding Scope in Javascript

How to change the context of a function in javascript

I'm trying to understand why in javascript, you might want to change the context of a function. I'm looking for a real world example or something which will help me understand how / why this technique is used and what its significance is.
The technique is illustrated using this example (from http://ejohn.org/apps/learn/#25)
var object = {};
function fn(){
return this;
}
assert( fn() == this, "The context is the global object." );
assert( fn.call(object) == object, "The context is changed to a specific object." );
jQuery makes use of it to good effect:
$('a').each(function() {
// "this" is an a element - very useful
});
The actual jQuery code looks like this:
for ( name in object ) {
if ( callback.call( object[ name ], name, object[ name ] ) === false ) {
break;
}
}
If it just did callback( name, object[ name ] ) then this wouldn't be set to the current object in your iterator and you'd have to use the parameter instead. Basically it just makes things easier.
Please have a look at this example:
<script>
var el = document.getElementById('button');
el.onclick = function(){
this.value = "Press Me Again"; //this --> now refers to the the element button not on the window
}
//Another Example:
var Person = function(name,location){
this.name = name;
this.location = location;
alert(this.location);
}
var p2 = new Person("Samantha","California"); //this refers to the instance of the function Person(Person now acts as a class)
var p1 = Person(); // this refers to the window(Person simply acts as a simple function)
</script>
<button id="button1">Press Me</button>
The new keyword changes the context.
It's very useful when doing callbacks from AJAX requests:
function Person(_id, _name) {
this.id = _id;
this.name = _name;
};
Person.prototype.sayHi = function(greeting) {
alert(greeting + " from " + this.name);
};
Person.prototype.loadFromAJAX = function(callback) {
// in this example, it's jQuery, but could be anything
var t = this;
$.get("myurl.php", function(data) {
callback.call(t, data.greeting);
});
};
Actually, that's a pretty crappy example.
There are tons of uses of it in jQuery. For example, the jQuery().get() function:
get: function( num ) {
return num === undefined ?
// Return a 'clean' array
Array.prototype.slice.call( this ) :
// Return just the object
this[ num ];
}
It's using the functions of the Array prototype but in the context of the jQuery object.
A real world example that i've encountered:
If you add a function as an event handler to a DOM element and if you use "this" inside that function, "this" will refer to the DOM element that you added the event handler to.
But that function might be a method of an object and you want the "this" keyword used inside it to refer to the owner object...so you need to change the context so that "this" will not refer to the DOM element but will refer to the owner object.
You can easily change the context of a function in jquery using the proxy() function.
See this question:
jquery "this" binding issue on event handler (equivalent of bindAsEventListener in prototype)
and the first answer
bind function might be what you're looking for, bind function returns a new function with in the context that you passed in , a real world scenario could be when you are using jquery delegates to attach some behavior to a dom element, and you want the callback being execute in a different context. 'cause the default context in a jquery delgate is the dom object that is bound to the handler , which means you can't access any property besides the properties that belongs to the dom object
I always find myself in the need of having different context when using setTimeout and jQuery has a handy function $.proxy which does the trick:
function iAmCalledAfterTimeout()
{
alert(this.myProperty); //it will alert "hello world"
}
setTimeout($.proxy(iAmCalledAfterTimeout, {myProperty:"hello world"}), 1000);

Categories