PDA

View Full Version : __proto__ : IE củ chuối quá !



sacroyant
01-06-2009, 02:50
Mấy hôm trước rảnh rỗi ngồi code lại trang chủ (http://sacroyant.googlepages.com/index.htm?nl=vi), tình cờ phát hiện thêm 1 điểm đáng chán của IE.

Chả là tớ gom các đối tượng cửa sổ giả lập vào 1 class để dễ quản lý theo tầng. Class ấy có dạng thế này :



function Window(id, width, height, content, url, title, icon){
this.id=id;
this.width=width||200;
this.height=height||100;
this.title=title;
this.content=content||'';
this.icon=icon||'';
this.url=url||'';
this.state=0;
this.zIndex=0;
this.top=0;
this.left=0;
this.cursorX=0;
this.cursorY=0;
this.topToPoint=0;
this.leftToPoint=0;
this.iconPath='';
this.modal=false;
this.draggable=false;
this.minimizable=false;
this.getState=function(){return this.state}
this.setOrder=function(z){
...
}
this.init=function(){
...
}
this.display=function(){
...
}
this.focus=function(){
...
}
..........
}

Sau đó tớ nghĩ đến 1 số hộp thoại nhận dữ liệu đơn giản, nó hiển thị ở tầng trên như 1 cửa sổ, nhưng không phải là cửa sổ, nó cũng di chuyển được nhưng không thể thu nhỏ, không chiếm chỗ trong stack phân tầng, không thể chứa 1 inline frame... Túm lại nó khá giống các cửa sổ nhưng không phải là cửa sổ. Nếu đặt ra các thuộc tính để phân biệt thì rườm rà code, nếu viết riêng 1 class khác thì không lợi dụng được những điểm tương đồng giữa 2 lớp. Thế nên tớ chọn giải pháp viết 1 class Dialog sao chép toàn bộ các methods và properties của class Window sang, như sau :


function Dialog(id, width, height, content, title){
this.__proto__ = new Window(id, width, height, content, '', title, '');
this.modal=true;
}

Rất tuyệt, việc gán mọi thuộc tính và phương thức từ lớp này sang lớp kia với __proto__ khiến cho code gọn không thể hơn được. Chrome, FireFox, Opera đều chạy ngon lành.

Ấy thế mà thằng IE đếch hiểu ! Nó bắt mình phải tạo 1 đối tượng trung gian rồi gán từng Method, từng Property qua Dialog, khiến cho class trở nên như vầy :no:


function Dialog(id, width, height, content, title){
if(this.__proto__) this.__proto__ = new Window(id, width, height, content, '', title, '');
else{
var k=new Window(id, width, height, content, '', title, '');
this.drop=k.drop;
this.setPosition=k.setPosition;
this.moving=k.moving;
this.startMove=k.startMove;
this.makeDraggable=k.makeDraggable;
this.getCursorPos=k.getCursorPos;
this.getWinsize=k.getWinsize;
this.setState=k.setState;
this.getState=k.getState;
this.setOrder=k.setOrder;
this.getOrder=k.getOrder;
this.close=k.close;
this.focus=k.focus;
this.display=k.display;
this.init=k.init;
this.draggable=k.draggable;
this.minimizable=k.minimizable;
this.id=id;
this.width=width;
this.height=height;
...
}
this.modal=true;
}


Nhìn chuối không thể tả ! Các bác có giải pháp nào hay hơn để xử lý tình huống trên cho MSIE không nhỉ :helpsmili

V.O.S
01-06-2009, 04:31
Ha ha, bác pro quá, nhìn chóng mặt. Nhưng chắc phải chịu vậy thôi chứ bít sao giờ

trinhdiep
01-06-2009, 19:19
bạn có thể tường minh hơn một chút xíu là được.
<code>
=======
function Dialog(id, width, height, content, title){
this.modal=true;
}
Dialog.prototype= new Window(id, width, height, content, '', title, '');
=======
</code>
mình nghĩ __proto__ chỉ là một shortcut

[=========> Bổ sung bài viết <=========]

oh. nhầm nhầm. nè không ổn lắm
<code>
=======
function Dialog(id, width, height, content, title){
var proto = new Window(id, width, height, content, '', title, '');
proto.modal=true;
return proto;
}
=======
</code>

sacroyant
01-06-2009, 20:46
@ V.O.S : bác quá lời, em chỉ là amateur tập code chơi thôi. Không qua trường lớp nào đâu.

@ trinhdiep :

Cảm ơn bạn có gợi ý hay. Bạn chỉ gần đúng rồi. Mình sửa lại một chút là được.

Theo cách nghĩ ban đầu của mình, Dialog không phải là lớp con của Window, tuy chúng gần giống nhau. Tương tự mèo và chuột chứ không phải mèo và động vật. Viết theo cách bạn nêu sẽ sinh lỗi, cụ thể như ví dụ sau :


function Mouse(name){
this.name=name;
this.talk=function(){
alert('My name is '+this.name);
}
}

function Cat(name){}

Cat.prototype=new Mouse(name);

var Jerry=new Mouse('Jerry');
Jerry.talk();

var Tom=new Cat('Tom');
Tom.talk();


Vì ở dòng Cat.prototype=new Mouse(name);, tham số name là undefined. Cho nên Jerry sẽ nói được tên nó còn Tom thì không.

Nhưng code sẽ chính xác khi được sửa thành :


function Mouse(name){
this.name=name;
this.talk=function(){
alert('My name is '+this.name);
}
}

function Cat(name){this.name=name;} // định nghĩa lớp Cat

Cat.prototype=new Mouse(); // gán prototype từ Mouse sang Cat

var Jerry=new Mouse('Jerry');
Jerry.talk();

var Tom=new Cat('Tom');
Tom.talk();

Lúc này cả Tom và Jerry sẽ đều nói ra được tên mình.

Vậy là tớ đã biết cách viết lại class Dialog, sao cho nó là một class khác biệt mà lại có được những methods và properties như class Window. Một cách viết chung cho cả trình duyệt chuẩn lẫn trình duyệt củ chuối :)


function Dialog(id, width, height, content, title){
this.id=id;
this.width=width;
this.height=height;
this.title=title;
this.content=content;
this.icon='';
this.url='';
this.modal=true;

this.prototype=new Window();
}


Bổ sung :

__proto__ là một thuộc tính liên quan đến hiện thể, khác biệt với prototype là thuộc tính liên quan đến lớp đối tượng. Khi tạo ra một hiện thể, chẳng hạn Jerry=new Mouse, thì thuộc tính prototype của class Mouse sẽ được sao chép sang thuộc tính __proto__ của Jerry, giúp cho Jerry có được mọi khả năng của lớp Mouse.

trinhdiep
01-06-2009, 20:59
nói cung thì bạn vẫn sai
>Vì ở dòng Cat.prototype=new Mouse(name);, tham số name là undefined. Cho nên Jerry sẽ nói được tên nó còn Tom thì không.

cái nè mình đã nói là nhầm mà.

>this.prototype=new Window();

cái nè nó sẽ không hiểu là prototype. prototype không sử dụng như vầy.
nghĩ linh tinh lại ra cũng khá hay.

function Dialog(id, width, height, content, title){
Window.call(this,[id, width, height, content, '', title, '']);
this.modal=true;
}

sacroyant
02-06-2009, 02:54
nói cung thì bạn vẫn sai
>Vì ở dòng Cat.prototype=new Mouse(name);, tham số name là undefined. Cho nên Jerry sẽ nói được tên nó còn Tom thì không.

cái nè mình đã nói là nhầm mà.

>this.prototype=new Window();

cái nè nó sẽ không hiểu là prototype. prototype không sử dụng như vầy.
nghĩ linh tinh lại ra cũng khá hay.

function Dialog(id, width, height, content, title){
Window.call(this,[id, width, height, content, '', title, '']);
this.modal=true;
}

Sử dụng call như kiểu của bạn cũng đã được nhắc đến ở đây (http://javascript-reference.info/correct-oop-for-javascript.htm).

Đúng là cách viết


this.prototype=new Window();

sẽ sinh lỗi. Phải viết bên ngoài hàm khởi tạo Dialog như trong trường hợp Tom & Jerry mới chính xác.


function Dialog(id, width, height, content, title){
...
}
Dialog.prototype=new Window();

Cảm ơn bạn :w00t: