There was a bug in my Omtose Phellack
Sorry, Bucharest, I will try to release a patch this evening.
Now if you execute var f=createMyFunction(); f(); you get a message box with a value of 11. The x variable is remembered, even if in the scope of a function that is not longer in execution. I will show you later how you can create truly private members of a class or function. Well, in Javascript there are no classes, only functions, but they have a different meaning from, let's say, functional programming.
function createMyFunction() {
var x = 11;
return function () {
alert(x);
};
}
you will get an alert with the value 10. The only scope is function scope in Javascript, meaning that to get the same effect as a block scope, the previous example should have looked like this:
if (condition) {
var x = 10;
}
alert(x);
and now you would get undefined.
if (condition) {
(function () {
var x = 10;
})();
}
alert(x);
The code above would display false. Why? because there is an equality between different types and they are both converted into... numbers! true gets an internal representation of the true value, while 'true' gets the value NaN, as it is not a number. And they are not equal. The condition itself is satified, because x is not empty.
var x = 'true';
if (x) alert(x == true);
This is better than using a variable as a condition of 0 would not execute an if block.
null == null //true
undefined == null //true
0 == null // false!
This is faster because byId is a closure and it gets a reference to the document (slow global variable) at its creation and remembers it in the environment. Every time you execute it, it will use the closest scope to find the variable and it will be faster. On my Internet Explorer 8, byId is faster than document.getElementById with 22%.
var byId = (function () {
var D = document;
return function (id) {
return D.getElementById(id);
};
})();
var x = 10;
(function () {
alert(x);
x--;
if (x > 0) argument.callee();
})();
This code defines an empty function called MyClass. You use it as a type and create instances of it by using the new operator. The first alert will show 'undefined' because the instance has no someProperty member. We then set it in the prototype and so it will be seen in any of the instances of MyClass, so the second alert will show 'set'. Then we set the actual value directly in the object. The third alert will display 'overwritten'. Delete the value (unset it) and the fourth alert will display 'set' again.
function MyClass = {};
var m = new MyClass();
alert(m.someProperty);
MyClass.prototype.someProperty = 'set';
alert(m.someProperty);
m.someProperty = 'overwritten';
alert(m.someProperty);
delete m.someProperty
alert(m.someProperty);
Here we create a MyClass object that inherits from ParentClass. In its constructor we apply the ParentClass function in the context of the MyClass instance (if we want to), then we create a new temporary F function in order to copy the prototype, but not whatever values are set via the constructor and we set an instance of it as the prototype for MyClass. Then we recreate the constructor of MyClass in its prototype, since it was overwritten.
function MyClass(msg) {
// optional
// ParentClass.apply(this,msg);
}
var F = new Function();
F.prototype = Parent.prototype;
MyClass.prototype = new F();
MyClass.prototype.constructor = MyClass;
(function () {
// base class
Animal = (function () {
// private member
var _version = '0.9';
return function () {
// priviledged getter (public, with access to the private member)
this.getVersion = function () {
return _version;
};
// priviledged setter
this.setVersion = function (value) {
_version = value;
};
};
})();
// prototype public method (only one referenced in all instances of Animal)
Animal.prototype.MakeNoise = function () {
throw "Abstract animal class must be inherited";
};
// prototype public method
Animal.prototype.getType = function () {
throw "Abstract animal class must be inherited";
}
// child class inherits from Animal
Duck = (function () {
// private member
var _type = 'Duck';
return function () {
// call the base constructor
Animal.call(this);
// priviledged getter (no setter for _type!)
this.getType = function () {
return _type;
}
// set version using base class method
this.setVersion('1.0');
// hide base class method (emulation of protected methods.
// of course, one can use delete a.setVersion
// and then access the base method)
this.setVersion = function () {}
};
})();
// copy the base class prototype
var F = new Function();
F.prototype = Animal.prototype;
// set it as the parent prototype
Duck.prototype = new F();
// prototype public method
Duck.prototype.MakeNoise = function () {
alert('Quack!');
};
})();
var a = new Animal();
alert(a.getVersion()); // 0.9
try {
alert(a.getType()); // error, abstract getter
} catch(e) {
alert("error! (" + e + ")");
}
try {
a.MakeNoise(); // error, abstract method
} catch(e) {
alert("error! (" + e + ")");
}
a = new Duck();
a.setVersion('999'); // no effect, since setVersion was replaced with empty function
alert(a.getVersion()); // 1.0
alert(a.getType()); // 'Duck'
a.MakeNoise(); // 'Quack!'
Now go into the designer and modify the Text property of InnerTag. You will notice that it will be saved as a hyphen attribute, while adding items to the Items collection would render the list items as children in the BaseClass tag:
public class BaseClass:ListControl
{
private InnerTagClass mInnerTag;
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
[NotifyParentProperty(true)]
public virtual InnerTagClass InnerTag
{
get
{
if (mInnerTag==null)
{
mInnerTag=new InnerTagClass();
}
return mInnerTag;
}
set
{
mInnerTag = value;
}
}
}
Now, an InnerDefaultProperty is still an InnerProperty. You can put the ListItem inside an Items tag and it will still work, and also you can add an InnerTag tag with a Text attribute and it will work as well! However, if you go into the designer and you change the Text for the InnerTag property you get the changed property as an attribute and the previous InnerTag tag, with the old value. That is not acceptable.
<local:BaseClass ID="BaseClass1" runat=server InnerTag-Text="Test">
<asp:ListItem>Test</asp:ListItem>
</local:BaseClass>
Now editing in the designer will create the Items tag and add the list items to it and an InnerTag tag with a Text attribute! But when you type it in source view, you get intellisense for both the Items tag and the ListItem tag! Adding only list items to the control works just like an inner default property.
public class InheritedClass : BaseClass
{
[PersistenceMode(PersistenceMode.InnerProperty)]
public override System.Web.UI.WebControls.ListItemCollection Items
{
get
{
return base.Items;
}
}
[PersistenceMode(PersistenceMode.InnerProperty)]
public override InnerTagClass InnerTag
{
get
{
return base.InnerTag;
}
set
{
base.InnerTag = value;
}
}
}