google+javascriptbanktwitter@js_bankfacebook@jsbankrss@jsbank






Phương thức ảo của JavaScript Thêm một bài viết khác nói về hàm/lớp trừu tượng trong ngôn ngữ lập trình JavaScript hướng đối tượng. Bạn có thể tìm hiểu kĩ hơn thông qua bài viết này với các ví dụ minh họa đơn giản.


Nhãn: phương thức ảo, lớp trừu tượng, hàm trừu tượng, JavaScript hướng đối tượng

Miễn phí web hosting 1 năm đầu tại iPage



Nếu bạn vẫn còn đang tìm kiếm một nhà cung cấp hosting đáng tin cậy, tại sao không dành chút thời gian để thử với iPage, chỉ với không quá 40.000 VNĐ/tháng, nhưng bạn sẽ được khuyến mãi kèm với quà tặng trị giá trên 10.000.0000 VNĐ nếu thanh toán cho 24 tháng ~ 900.000 VNĐ?

Có trên 1 triệu khách hàng hiện tại của iPage đã & đang hài lòng với dịch vụ, tuyệt đối chắc chắn bạn cũng sẽ hài lòng giống họ! Quan trọng hơn, khi đăng ký sử dụng web hosting tại iPage thông qua sự giới thiệu của chúng tôi, bạn sẽ được hoàn trả lại toàn bộ số tiền bạn đã sử dụng để mua web hosting tại iPage. Wow, thật tuyệt vời! Bạn không phải tốn bất kì chi phí nào mà vẫn có thể sử dụng miễn phí web hosting chất lượng cao tại iPage trong 12 tháng đầu tiên. Chỉ cần nói chúng tôi biết tài khoản của bạn sau khi đăng ký.

Nếu muốn tìm hiểu thêm về ưu / nhược điểm của iPage, bạn hãy đọc đánh giá của ChọnHostViệt.com nhé!
Thử iPage miễn phí cho năm đầu tiên NGAY

I love JavaScript. Yeah, you heard me right. I remember being part of a groundbreaking project back in 2002 where I was thrown into the world of JavaScript and was given the mission to go crazy with it. Several hundred thousand lines and a fully functional in-memory SQL engine later, I gained huge respect for the language that many of my co-workers saw only as a toy language for browsers. Oh, how far we have gone since then. To me, JavaScript is kind of like SmallTalk with a C syntax, and the expressiveness and power of the language is impressive.

JavaScript is not enough to make your sites run, we need HTML, PHP, .NET, Java in the server side. PHP is also the most popular language to build websites. Certainly, PHP is a server language, you must need a PHP Hosting place to host your PHP files. jsB@nk recommends PhpHost.org if you need a PHP webhost with features: easy control panel, super fast servers, 24/7 good & fast support.

One of my favorite patterns I use all the time is how to implement virtual functions in a simple fashion. There are heavier patterns such as mix-ins and frameworks to do all of it, but honestly, when you are building a quick app that maxes out at only a few thousand lines of code, sometimes I think that its just simpler to go for hand-to-hand combat.

We have used this technique heavily in Alice, a new micro-library focusing on fancy visual effects using CSS3 2D and 3D facilities. We created reusable parts in a base class, and implemented virtual functions in a derived class, where logic that is specific to a particular effect is implemented. I use quotes everywhere here because as youll see, the traditional Object Oriented notions of Classes, Base and Derived are somewhat fuzzy with JavaScript.

So what am I talking about? Lets say for example that you implement a piece of logic where you need to collect DIVs nested in a given DIV. You may write very simple code such as:

function getSubDIVs(nodeId) {
    var node = document.getElementById(nodeId);
    var DIVs = [];
    for (var i = 0; i < node.childNodes.length; i++) {
        var e = node.childNodes[i];
        if (e.nodeName.toLowerCase() == "div")
           DIVs.push(e);
    }
   return DIVs;
 }

For those unfamiliar with JavaScript, DIVs is declared as an array, and push is a method to add a new element at the end of that array. The rest should be pretty self-explanatory. Overall, this code is simple and straightforward. But what if tomorrow, you need to do other things with the sub-DIVs? You need to abstract some of the logic. For example:

function getSubDIVs(nodeId) {
    var node = document.getElementById(nodeId);
    var DIVs = [];
    for (var i = 0; i < node.childNodes.length; i++) {
        var e = node.childNodes[i];
        if (doSomething(e) == true)
         DIVs.push(e);
    }
   return DIVs;
 }

JavaScript is a wonderful language, and there are two aspects in particular that makes it extra special:

  • Every value is an Object.
  • Functions are like any other values.
  • Functions run within a dynamic context (what this refers to).

The second property provides us with one solution already. Functions in JavaScript are like any other object, so you can just pass one in as any other parameter.

function getSubDIVs(nodeId, doSomething) {
    var node = document.getElementById(nodeId);
    var DIVs = [];
    for (var i = 0; i < node.childNodes.length; i++) {
        var e = node.childNodes[i];
        if (doSomething(e) == true)
         DIVs.push(e);
    }
   return DIVs;
 }

Note that doSomething is now a parameter, so I can pass in any function I want in there, dynamically:

function filterOnlyDIVs(e) {
    return (e.nodeName.toLowerCase() == "div");
 }
getSubDIVs("myNodeId", filterOnlyDIVs);

JavaScript even support anonymous inline functions, which allows you to write even simpler code:

getSubDIVs("myNodeId",
           function(e) { return e.nodeName.toLowerCase() == "div"); }
          );

You can inline the function definition itself, and pass it in as a parameter. Neat, right? That is cool, but there is something missing. What if you are dealing with objects? What if your function needs to have access to some state or information? For example, lets assume the following JavaScript object definition:

function MyObject {
    this.count=0;
    this.filterOnlyDIVs = function(e) {
       if (e.nodeName.toLowerCase() == "div") {
    	   ++this.count;
    	   return true;
    	 }
       return false;
    }
 }

Now you have a problem. A function is a value in and of itself, but there are tricks in terms of defining which context it actually runs in, that is, what does this mean? If I repeat my previous JavaScript code, then Ill have quite a surprise.

var Obj = new MyObject();
getSubDIVs("myNodeId", MyObject.filterOnlyDIVs);
alert(Obj.count);

Trick question: what will be printed out? No matter what, youll get 0 because several pernicious things are happening under the covers:

  • We are passing in a pointer to the function, in and of itself, without any context of any object.
  • When the code ++this.count; runs, it runs out of the function itself; remember, functions are objects too.
  • When you print the value of count, you are then using your object instance, and the value is 0 no matter what. You implicitly defined dynamically a variable called count for the function itself, so if you did alert(getSubDIVs.count), thats where youd see the value… Or would you? Maybe its MyObject.filterOnlyDIVs.count? Play around, and see for yourself. Hint: functions are Objects too.

JavaScript can be tricky that way, and thats the way it works. But we can use it to our advantage with an interesting pattern. We only have to do one very simple, but major, thing:

function getSubDIVs(nodeId) {
    var node = document.getElementById(nodeId);
    var DIVs = [];
    for (var i = 0; i < node.childNodes.length; i++) {
        var e = node.childNodes[i];
        if (this.doSomething(e) == true)
         DIVs.push(e);
    }
   return DIVs;
 }

All we have done now is to say that doSomething is no longer passed in as a parameter. Instead, it will be executed in the context of this. So, the more astute amongst you will ask But what is this? I thought the function was itself an Object, and thats what this referred to? Beautiful question! If you just call the method, you will get an error, because there is no doSomething function out of this.

getSubDIVs(nodeId);

So this is the time I am asking you to think about virtual functions in traditional Object Oriented languages. What would you do here? Youd define doSomething as a method, and override it in a child class. You cant do that per se in JavaScript, but you can do something very cool: you can attach that function dynamically to any object you have.

function MyObject {
    this.count=0;
    this.doSomething = function(e) {
       if (e.nodeName.toLowerCase() == "div") {
    	   ++this.count;
    	   return true;
    	 }
       return false;
    }
   this.getSubDIVs = getSubDIVs;
 }

This is so beautiful and elegant – you are effectively assembling your object on the fly out of parts. You declare a new method for MyObject (they can have the same name, but its not necessary) and assign to it the base method getSubDIVs (which is really a global function). Now, when you make your call, and when getSubDIVs executes, it now does so in the context of your object (where this.count is meaningful), and everything in the world is good.

var Obj = new MyObject();
Obj.getSubDIVs("myNodeId");
alert(Obj.count);

This is what goes on:

  • You create an instance of MyObject called Obj.
  • You call the MyObject.getSubDIVs method on Obj.
  • This in fact calls the global function getSubDIVs.
  • This happens without any level of indirection or performance penalty since the MyObject.getSubDIVs variable is in effect the global function getSubDIVs.
  • In the global function getSubDIVs, this is actually Obj, so ++this.count; works your Obj.
  • When you then print out Obj.count, you get the right count.

And voila! You have pieced together, manually, the core tenets of Object Oriented development and encapsulated reusable code, which you customize with derived functionality. You have encapsulated a piece of logic somewhere (here, in a global function). Then in that function, you make a call to a virtual function, which you then implement separately in a class. You tie it all together by attaching the base method to that class.

You can use frameworks to do this, but honestly, I think that its so simple that, unless you work on very large projects, you are better off with direct hand-to-hand combat. JavaScript allows you to write well encapsulated code, so go ahead and do it!

JavaScript theo ngày


Google Safe Browsing McAfee SiteAdvisor Norton SafeWeb Dr.Web