Introduction to A Prototype-based Language - JavaScript

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 are registered 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 printed equal 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");

else if (window.chrome)

    document.write("chrome");

else if (window.mozInnerScreenX != null)

    document.write("firefox");

else if (document.all)

    document.write("ie");

else

    document.write("other");

 

Nevertheless, developers have to be more careful than programming with Java because wrongly-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(){return 1;};document.write((typeof a)+"<br/>");//function

 

To give a further explanation, arrays are regarded as objects 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 i in 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

public int a=1;//a new property named ‘a’

}

 

As an object-oriented language, JavaScript prototypes can be inherited 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

class Foo2 extends 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 to access 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{

public void a(){}

}

class Foo2 extends Foo1{

public void 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 a static 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:

 

public class Foo{

    public int a=1;

    public String b="hello world";

    public boolean c=true;

    public void 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 to manage 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;

public class Foo{

    public String _text;

    public Foo(String t){

       _text=t;

    }

    public void write(){

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

    }

}

 

js/sample/Foo.java

package js.sample;

public class Foo{

    public String _text;

    public Foo(String t){

       _text=t;

    }

    public void write(){

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

    }

}

 

Test.java

public class Test{

    public static void 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

《算法导论》Hardcover版的引言(Introduction to Algorithms - Hardcover Edition)是一本经典的计算机科学教材。该版本不仅在内容上与平装版相同,还具有精美的硬皮封面,能够更好地保护书籍,并增添一份高质感和专业感。 首先,这本书是由Thomas H. Cormen等四位作者共同编写。他们是计算机科学领域的权威人物,在算法研究和教育方面具有丰富的经验。这本书的目的是为计算机科学专业的学生和从业人员提供系统而全面的算法知识,帮助他们深入理解和应用算法。 《算法导论》Hardcover版首先介绍了算法设计和分析的基础知识,包括分治法、贪婪算法、动态规划和回溯法等。接着,书中详细阐述了各种经典算法,如排序、图算法、字符串匹配、高级数据结构等。此外,书中还介绍了算法的优化技巧和应用领域,例如算法的并行化和近似算法。 与平装版相比,Hardcover版的封面更加美观,书页由高品质纸张制成,更加耐用。这使得读者在长时间研究和使用这本书时,能够更好地保存它的完整性和精美外观。此外,Hardcover版也更加适合作为礼品或收藏品,体现了读者对该书的重视和对算法学习的热爱。 总之,《算法导论》Hardcover版是一本内容丰富、思想深刻的算法教材,通过系统化的介绍和实例,帮助读者深入理解和应用各种算法。同时,Hardcover版的精美外观和耐用性也增强了读者在日常使用和收藏方面的满意度。无论是学习算法的新手还是资深专家,都能从这本书中获得极大的收益。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值