Introduction to A Prototype-based Language - JavaScript

来源:互联网 发布:淘宝下拉框词一键提取 编辑:程序博客网 时间:2024/05/19 23:26

by Zhiji Gu

Recently, I have done nothing more than experencing JavaScript, a prototype-based language. We may have been familiar with a class-based language, like Java. Plus some outsiders always confused by the two languages because of their similar names, I would like to compare them in detail today.

 

 

Variables in JavaScript areregistered automatically by its interpreter when a value is assigned even if we do not define them in advance. However, new properties of some object that show ‘undefined’ if printedequal to ‘null’ without any errors being raised. This feature builds its flexibility and strength to run on different browsers, though there are some disadvantages, too. As we know, browsers like IE and Firefox are not exactly the same. So there is a simple and fast way to distinguish current main-stream browsers:

 

if(window.opera)

   document.write("opera");

elseif(window.chrome)

   document.write("chrome");

elseif(window.mozInnerScreenX != null)

   document.write("firefox");

elseif(document.all)

   document.write("ie");

else

   document.write("other");

 

Nevertheless, developers have to be more careful than programming with Java becausewrongly-spelt words cannot be recognized if the concequence is not manifest. JavaScript is not compiled before running and all errors like this will not be reported by its interpreter. Moreover, new JavaScript variables without definition are registered by the interpreter in the global region where data are not secure in a complex mashup website and this may cause unexpected errors. Do remember defining variables in the block where they should take effect so that they cannot be changed with evil purposes. To define a variable is like this:

 

var foo=1;

 

From the demostration, we see that type of the variable ‘foo’ is not declared. What’s more,type of a variable in JavaScript is not fixed. I mean that we can give a string of “hi” to “foo” even though it was a number. This may also lead to problems when the type of some variable is uncertain. But fortunately, JavaScript has operator “typeof” to show the type as a piece of string. Here is an experiment:

 

var a;

a="";document.write((typeof a)+"<br/>");//string

a=true;document.write((typeof a)+"<br/>");//boolean

a=1;document.write((typeof a)+"<br/>");//number

a=1.2;document.write((typeof a)+"<br/>");//number

a=(1,2);document.write((typeof a)+"<br/>");//number

a=[1,2];document.write((typeof a)+"<br/>");//object

a=new Array(1,2);document.write((typeof a)+"<br/>");//object

a=null;document.write((typeof a)+"<br/>");//object

a=new Object();document.write((typeof a)+"<br/>");//object

a={a:1,b:2};document.write((typeof a)+"<br/>");//object

a=function(){return1;};document.write((typeof a)+"<br/>");//function

 

To give a further explanation, arrays are regarded asobjects in JavaScript, so both “[1,2]” and “new Array(1,2)” result in “object” (these are two ways to express arrays). Sometimes, we can even visit data members of an object the way to iterate elements in an array:

 

function dump(obj, container) {

   var a= "<table border=1><tr><th bgcolor=/"blue/" colspan=2>"

          + obj + "</th></tr>";

   for(var iin obj) {

      a += "<tr><td>"+ i.toString() + "</td><td>"+ obj[i] + "</td></tr>";

   }

   a += "</table>";

   container.innerHTML += a;

}

 

As an addition, variables are not registered for parameters (returning null) in a JavaScript function if real values are not given when the function is called. Look here:

 

function foo(v){

   document.write("v");

   document.write(v==null?" ":"=");

   document.write(v);

   document.write("<br />");

}

foo();//v undefined

foo(1);//v=1

 

From this piece of code, we can find that parameters do not play a big role in naming a JavaScript function unlike Java method names, and there will be another evidence when it is time for function declaration by assignment.

 

 

Both class-based and prototype-based languages serve the object-oriented developers. I guess JavaScript must had been designed in a procedure-oriented type for it remains the features even when it has become object-oriented and I personally find that everything can be assigned in JavaScript! As a basic concept, in Java, we have classes representing extended types of objects while a prototype is the counterpart in JavaScript.

 

However, there is a huge difference in the declaration between a prototype and a class. Actually, we do not have to declare a prototype intentionally, because a function and its properties form a prototype automatically as long as I add a member to its property named 'prototype'. Then we view the original function as a constructor of the prototype. For example,

 

function Foo(){}//the constructor

Foo.prototype.a=1;//a new property named ‘a’

 

To compare, here is an example for Java:

 

class Foo{

public Foo(){}//the constructor

publicint a=1;//a new property named ‘a’

}

 

As an object-oriented language, JavaScript prototypes can beinherited when they are made to be the prototype of a new prototype (perhaps we’d better call it ‘the prototype of a new type’, or ‘the original type of a new type’). We can do this simply by giving an object generated from its prototype to another prototype’s property, ‘prototype’.

 

function Foo1(){}//the parent prototype

function Foo2(){}//a new type

Foo2.prototype=new Foo1();//inherits

 

The example in Java:

 

class Foo1{}//the parent class

classFoo2extends Foo1{}//A new class inherits its parent class.

 

Excitingly, by coding with JavaScript, we can even do things that cannot be realized in Java. In C, function pointers help us call different procedures by the same name and this can also be done in JavaScript though no pointer exists there. I said what? – everything can be assigned!

An anonymous function can be assigned to a named variable so that the function has its name:

 

var Foo=function(param){};//declare

Foo("hello world");//call

 

Assign a function name to an alias:

 

function Foo1(){};//declare

var Foo2=Foo1;//name again

Foo2();//call:equivalent to calling Foo()

 

As a result, functions declared in this way can even be cancelled!

 

var Foo=function(){};//declare

Foo=null;//cancel

 

In this way, methods can be overridden after inheriting their parents. But here comes the problem. The keyword ‘super’ makes it possible toaccess the methods declared in the parent class and that are overriden and hidden, whereas in JavaScript, we have just changed the content of an overriden function and completely discarded the old version. However, the solution is simple here.

 

var Foo1=function(){};//declare a type

Foo1.prototype.a=function(){};//declare a method

var Foo2=function(){};//declare a new type

Foo2.prototype=new Foo1();//inherit

Foo2.prototype._a=Foo2.prototype.a;//preserve

Foo2.prototype.a=function(){//override

this._a();//call the preserved version

//TODO:something else

};

 

A corresponding Java version:

 

class Foo1{

publicvoid a(){}

}

class Foo2extends Foo1{

publicvoid a(){

super.a();

//TODO:something else

}

}

 

An object can be deemed as a copy of a prototype in JavaScript (except for static members that will be mentioned later on) and all members in the prototype are visible directly in the object once initialized or using the keyword ‘this’ (because ‘this’ refers to the current object though it is inside a declaration block), unlike the situation where we modify a prototype on the property called ‘prototype’. Also, we can add new properties to a constructed object rather than its prototype. To clarify, let me compare modifying a prototype and accessing an object (including using ‘this’):

 

function Foo(){

   this.a=1;//modify property 'a' using 'this'

}

Foo.prototype.b=2;//modify property 'b' using 'prototype'

var copy=new Foo();

copy.c=3;//modify property 'c' on the object

document.write(copy.a+copy.b+copy.c);//access properties directly on an object

 

There is anothor possible mistake that the property, ‘prototype’ may be omitted when adding a new member to the prototype, but it is not wrong in syntax. It is to add astatic member to the prototype, which shares a similar meaning with a static member in Java – a static data member in JavaScript does not change individually for various copied objects but like a global variable inside its prototype. What’s important, a static member can only be accessed with the original prototype name. Here is the example:

 

function Foo(){}

Foo.prototype.a=1;//a normal property

Foo.b=1;//a static property

var f1=new Foo();

var f2=new Foo();

f2.a++;

Foo.b--;

document.write("f1.a:1=>"+f1.a+"<br />");//f1.a:1=>1

document.write("f2.a:1=>"+f2.a+"<br />");//f2.a:1=>2

document.write("Foo.b:1=>"+Foo.b+"<br />");//Foo.b:1=>0

 

Additionally, although static members in a Java class can be visited from its object on the basis of current Java versions, it is not recommended to do so. The best way is just coding like JavaScript, accessing static members with its class name.

 

Furthermore, JavaScript provides a kind of special syntax for filling structured data in static objects. If there is not a method (function) in a JavaScript object, it is a perfect information carrier. One of the reasons is that there is a clear structure. On the other hand, comparing with XML, another popular structured text format of today’s web technology, this feature of JavaScript is much simpler and faster (called JSON). With the help of the function eval(), JavaScript interpreters obtain and comprehend data directly without any more redundant symbols and additional parsers. This is how it looks like:

 

var foo= {

   a : 1,

   b : "hello world",

   c : true,

   get : function(a,b,c){

      this.a=a;

      this.b=b;

      this.c=c;

   }

};

 

And the following is the Java counterpart (the object ‘foo’), so as to explain the code above:

 

publicclass Foo{

   publicint a=1;

   public String b="hello world";

   publicboolean c=true;

   publicvoid get(int a,String b,boolean c){

      this.a=a;

      this.b=b;

      this.c=c;

   }

}

Foo foo=new Foo();

 

 

Packages in Java or namespaces in C++/C# divide programs into different categories and avoid conflicting names in the same scope and help gain greater complexity. Thanks to the increasing capacity and performace of new computers and their networks, JavaScript has no longer been simple scripts. Consequently, developers are thinking about ways tomanage JavaScript code in modules. Unfortunately, there is nothing like a package or a namespace in JavaScript, but objects in hierarchical structures may act like modules. We can assume that there are two prototypes sharing the same name ‘Foo’ but they are both needed at the same time. Therefore, I put them in two namespaces so that they do not get mixed up:

 

var js= {

   sample : {}

};

js.Foo= function(t) {

   this._text=t;

};

js.Foo.prototype.write= function(){

   document.write("js.Foo:"+this._text+"<br />");

};

js.sample.Foo= function(t) {

   this._text=t;

};

js.sample.Foo.prototype.write= function(){

   document.write("js.sample.Foo:"+this._text+"<br />");

};

var a= new js.Foo("hi a");

var b= new js.sample.Foo("hello b");

a.write();

b.write();

 

Java code:

 

js/Foo.java

package js;

publicclass Foo{

   public String _text;

   public Foo(String t){

      _text=t;

   }

   publicvoid write(){

      System.out.println("js.Foo:"+_text);

   }

}

 

js/sample/Foo.java

package js.sample;

publicclass Foo{

   public String _text;

   public Foo(String t){

      _text=t;

   }

   publicvoid write(){

      System.out.println("js.sample.Foo:"+_text);

   }

}

 

Test.java

publicclass Test{

   publicstaticvoid main(String[] args){

      js.Foo a=new js.Foo("hi a");

      js.sample.Foo b=new js.sample.Foo("hello b");

      a.write();

      b.write();

   }

}

 

At last, I would like to mention a ‘drawback’ of JavaScript that I did not plan to write about. It is access limits of JavaScript objects. We know that there are four types of limits in Java, which are ‘private’, ‘protected’, ‘package/default (no keyword to describe)’ and ‘public’. However, JavaScript does not need such limits for we can never trust the code run on clients. Everybody can see the source code on the internet, or even manipulate the execution with the support of some tools. All in all, we expect speed, if possible.

 

Happy studying!

 

Zhiji Gu

February 9th-11th, 2011

Kunshan, China

原创粉丝点击