`

javascript中的OOP思想(-)

    博客分类:
  • HTML
阅读更多

    隨著AJAX的流行,javascript又被WEB程序員重視起來,網上呈現的許多框架和類庫都很好的解決了瀏覽器的兼容問題。不過我認為除非做大型項目(比如OA系統),否則我不贊成使用框架。
    一個prototype.js就幾十K,而Atlas.js有將近4百K,這些JS代碼是下載到本地由瀏覽器進行解釋執行的,如果再加一些其它的框架,瀏覽器不當掉才怪。
    前段時間我寫了同個JS的東東,可以說將面向對象發揮得淋漓盡致了!^_^:),並且兼容各大瀏覽器。 下面先貼一個拖動代碼,稍候會作解釋!

// JavaScript Document
/*
writer:solidluck(xishui)
created:2006/12/23
QQ:45671948----UC:75853187
Version:Beta 1.0
*/
var Browser = {
    //定義一個Browser對象用於檢測瀏覽器
    //IE的條件編譯
    /*@cc_on isIE : true, @*/
    isFF : window.navigator.appName.indexOf("Netscape") != -1 ? true : false
};
//如果是IE瀏覽器,就創建三個函數(待會詳細解釋)^_^
if(Browser.isIE) {
    var HTMLElement = new Function();
    var HTMLDivElement = new Function();
    var HTMLUnknownElement = new Function();
}
if(!Browser.isIE) {
    //這個函數用於搜索事件參數(用於非IE中)
    function SearchEvent()     {
        var func=SearchEvent.caller;
        while(func!=null)         {
            var arg=func.arguments[0];
            if(arg){
                if(String(arg.constructor).indexOf('Event') > -1){
                    return arg;
                }
            }
            func=func.caller;
        }
        return null;
    }
    //給非IE中的window的構造函數增加一個屬性event
    window.constructor.prototype.__defineGetter__( "event", function() { return SearchEvent(); } );
    //增加一個樣式對象,供讀操作
    HTMLElement.prototype.__defineGetter__( "currentStyle", function() { return this.ownerDocument.defaultView.getComputedStyle(this,null); } );
    //增加一個樣式對象,供寫操作(可以看作是currentStyle的寫版本)
    HTMLElement.prototype.__defineGetter__( "runtimeStyle", function() { return this.style; } );
    //增加一個attachEvent方法,用於綁定事件
    HTMLElement.prototype.attachEvent = function(eName,handler){
        var eType = eName.substring(2,eName.length);
        this.addEventListener(eType,handler,true);
    }
    if(Event) {
        //增加一個事件源屬性
        Event.prototype.__defineGetter__( "srcElement", function() { return this.target; } );
    }
}
//這個方法就重要了,改寫了document.getElementById()方法,用於實現非IE內核中HTML元素的綁定,實現 繼承
function $() { 
    if(!arguments.length) return;
    var elements = [];
    for(var i = 0;i < arguments.length;i++) {
        elements.push(document.getElementById(arguments[i]));
        if(Browser.isIE) {
            //如果綁定過,就不再進行綁定
            if(!elements[i].expand) {
                Global.copy(elements[i],HTMLElement.prototype);
                Global.copy(elements[i],elements[i].getType().prototype);
                elements[i].expand = true;
            }
        }
    }
    if(elements.length == 1)
        return elements[0];

    return elements;
}
var Global = {
    //Global對象的copy方法利用反射機制實現成員復制
    copy : function(without,object) {
        if(arguments.length != 2) return;
        if(!without || !object) return;
        for(var index in object) {
            if(without[index]) continue;
            without[index]=object[index];
        }
    }
}
Global.copy(HTMLElement.prototype,{
    //getType方法將成為所有HTML元素的一個方法。主要用於實現HTML各個元素的不同基類
    getType : function() {
        if(this.tagName.toUpperCase() != "DIV")
            return HTMLUnknownElement;
        return HTMLDivElement;
    }
});
Global.copy(HTMLDivElement.prototype,{
    //接下來就是對DIV元素所繼承的類進行擴展。我這裡只是實現了拖動
    parent : function() {
        var Parent = this.offsetParent,current;
        if(Parent.tagName.toUpperCase() == "BODY" || Parent.tagName.toUpperCase() == "HTML") {
            current = this;
        } else {
            current = Parent;
        }
        return current;
    },
    drag : function() {
        var _this = this.parent();
        var current = this;
        var doc = document.documentElement || document.body;
        this.runtimeStyle.cursor = "move";
        function down(e) {
            Global.down = true;
            Global.left = event.clientX - _this.offsetLeft;
            Global.top = event.clientY - _this.offsetTop;
            if(_this.setCaptrue)
                _this.setCaptrue();
            else if(window.captureEvents)
                window.captureEvents(Event.MOUSEMOVE|Event.MOUSEUP);
            document.body.onmousemove = function(e) {
                if(Global.down) {
                    _this.runtimeStyle.left = Math.min(Math.max((event.clientX - Global.left),0),doc.clientWidth - _this.clientWidth) + "px";
                    _this.runtimeStyle.top = Math.min(Math.max((event.clientY - Global.top),0),doc.clientHeight - _this.clientHeight) + "px";
                }
                return false;
            }
            document.body.onmouseup = function(e) {
                Global.down = false;
                if(_this.releaseCapture)
                    _this.releaseCapture();
                else if(window.releaseEvents)
                    window.releaseEvents(Event.MOUSEMOVE|Event.MOUSEUP);
                document.onmousemove = null;
                document.onmouseup = null;
                return false;
            } return false;
        }
        this.attachEvent("onmousedown",down);
    }
}); 
 


/*--------------源碼詳解 ---------------*/

if(Browser.isIE) {
    var HTMLElement = new Function();
    var HTMLDivElement = new Function();
    var HTMLUnknownElement = new Function();
}
 


 如果是IE內核的瀏覽器,就創建三個函數,我這裡創建的這三個函數名不是隨便取的。
在標准的DOM瀏覽器中(比如 firefox),HTMLElement是所有HTML元素的基類,而各個HTML元素又有各自的基類,比如DIV元素繼承了 HTMLDivElement類和HTMLElement,select元素耿繼承了HTMLSelectElement和HTMLElement類。
我之所以在IE內核的瀏覽器中創建FF中相同的類名函數,是因為接下來擴展就不需要再去檢測瀏覽器。夠方便!
__defineGetter__()和__defineSetter__()是屬性構造器。前者為讀,後者為寫。其實也就相當於C#中的get和 set。但這在IE中是不支持的。所以有點遣憾,覺得程序員們把太多的時間和精力浪費在兼容問題上了。
接下來講講兩種不同內核瀏覽器的事件模型吧(差別太大,以致於很多程序員只寫在IE運行的程序,不過我認為,作為一個合格的程序員,要寫就寫兼容的。即使是桌面應用程序,跨平台也是一個持久話題)。
IE內核的瀏覽器:一旦解發了事件,就會產生一個全局對象,這個對象自動成為window對象的一個成員屬性,通過window.event可以進行訪問(event對象只在事件觸發期間存在,一旦傳給相應事件的函數運行完畢,這個event對象將會自動銷毀)。
根據事件的類型,event對象會保存不同的信息。這些信息作為event的成員進行訪問。標准瀏覽器: 比如firefox瀏覽器,在執行事件時,需要傳遞一個參數來保存事件的相關信息。
一般可以通過如下代碼進行瀏覽器兼容:

document.onclick=function(e) { 
	var e=window.event||e; 
	var target=e.srcElement||e.target; 
	alert(target); 
}  


這裡用到了||運算符,它是一個短路運算符,比如有a||b,在執行時,首先會將a轉為boolean類型來進行測試,如果為true,那麼直接返回a的值(注意,是返回原值,而不是返回boolean類型的值),如果為false,那麼就去測試b(同樣轉為boolean類型來進行測試),當然,不管b 測試的結果是true或false,都會返回b的值(返回原值)。
不過如果要大量的使用事件,在寫兼容瀏覽器的代碼時,會重復很多,顯得很不簡潔。其實在firefox瀏覽器中,提供了一個靜態的Event對象。可以利用我剛才說過的__defineGetter__()屬性構造器來進行擴展Event(在觸發事件時,產生的事件對象其實是Event對象的一個實例),然後通過修改window的構造函數來得到一個跟IE兼容的event對象。下面解釋一下searchEvent方法。

function SearchEvent() 	{ 
	var func=SearchEvent.caller; 
	while(func!=null) 		{ 
		var arg=func.arguments[0]; 
		if(arg){ 
			if(String(arg.constructor).indexOf('Event') > -1){ 
				return arg; 
			} 
		} 
		func=func.caller; 
	} 
	return null; 
} 
 


這裡用到了caller,它是函數對象的一個屬性,指向調用者,如果a函數被b函數調用,那麼a.caller指向這個b(只能在函數內部使用 caller),否則返回null。
通過while循環一級一級的向上搜尋,直到找到為止。arguments是參數對象,只能在函數內部使用,表示當前函數的形參集合(對於arguments,比較怪異,它像一個集合,又像一個數組。卻不是集合也不是數組)。
這樣擴展以後,在使用時,就跟在IE中一樣方便,使代碼效率更高。
下面來解釋一下樣式對象。相信各位用過style對象了。如果樣式是在行內定義的,style肯定可以得到相關樣式的值(如果你定義了的話)。但如果樣式是一個外部文件呢。那麼通過style來進行讀取某個樣式值是行不通的。
換個思路,不管樣式定義在哪裡,在運行時,元素是肯定具備某些樣式的(如果定義了的話)。IE提供了一個currentStyle來進行讀取。FF中的要麻煩一些,不過好歹提供了相應的屬性。^_^:)。
下面著重講解一下$()方法的實現。貼代碼先:

function $() {  
	if(!arguments.length) return; 
	var elements = []; 
	for(var i = 0;i < arguments.length;i++) { 
		elements.push(document.getElementById(arguments[i])); 
		if(Browser.isIE) { 
			//如果綁定過,就不再進行綁定
			if(!elements[i].expand) { 
				Global.copy(elements[i],HTMLElement.prototype); 
				Global.copy(elements[i],elements[i].getType().prototype); 
				elements[i].expand = true; 
			} 
		} 
	} 
	if(elements.length == 1) 
		return elements[0]; 

	return elements; 
} 
 


首先確定綁定是在IE內核的瀏覽器中進行的。然後判斷元素的expand屬性是否存在(第一次綁定時,expand屬性是肯定不存在的,綁定之後,將 expand的值賦為true,那麼下一次執行$()方法時,就不再進行綁定)。

Global.copy(elements[i],HTMLElement.prototype); 

 

//通過繼承HTMLElement類,當前元素將會擁有getType()方法。getType()方法會根據元素返回相應的類(我這裡僅僅擴展了 DIV,如果某位網友想擴展別的,可以按照我的思路)。

Global.copy(elements[i],elements[i].getType().prototype); 
 

//這個時候已經有getType()方法了,執行之後將返回一個類,接著擴展這個類,那麼元素就會擁有這個類的所有成員。 寫個例子來拖動吧。。

好了,說了那麼多了,朋友們有問題可以跟我聯系。。。。^_^:)


分享到:
评论
1 楼 seven_cuit 2008-11-07  
文章写成这样让人怎么看!

相关推荐

    javascript的oop思想以及单例,工厂,观察者模式简例

    本篇文章将深入探讨JavaScript的OOP思想,并通过实际代码示例介绍单例模式、工厂模式和观察者模式。 首先,面向对象编程的核心概念是类和对象。在JavaScript中,虽然没有传统的类定义,但可以通过构造函数来模拟类...

    javascript oop模式讲解

    JavaScript OOP(面向对象编程)模式是编程领域中一种重要的设计思想,它允许开发者通过类和对象来组织和管理代码,提高代码的可重用性和可维护性。在这个讲解中,我们将深入探讨JavaScript中的OOP模式,特别是如何...

    javascript-OOP:JavaScript OOP

    JavaScript OOP,即JavaScript面向对象编程,是JavaScript语言中一种重要的编程范式,它使得代码更加结构化、可维护和可重用。在JavaScript中,OOP主要通过类(Class)和对象(Object)来实现,同时利用了封装、继承...

    oop与javascript

    在JavaScript中实现OOP主要依赖于原型继承和类的概念。 ##### 1. 对象与类 - **对象**:是具有属性和行为的实体。在JavaScript中,一切皆为对象。 - **类**:定义了一组拥有相同属性和方法的对象模板。虽然原生...

    OOP-PROJECT-

    在这个名为 `OOP-PROJECT--main` 的文件中,很可能是项目的主入口文件,它可能包含了项目的核心逻辑、初始化代码,或者是使用 OOP 思想构建的一些关键组件。要深入了解这个项目,你需要打开文件查看具体的代码实现,...

    js-oop-project-lvl1

    在JavaScript中,实现OOP主要通过构造函数、原型和类(ES6引入)。这个项目可能是让你创建一个或多个类,模拟实际问题中的对象和它们之间的关系。可能的任务包括定义属性和方法,理解实例化,以及掌握继承和多态等...

    oop-js-platzi:@juandc 在 @Platzi 上的 JavaScript 面向对象编程课程

    JavaScript 面向对象编程(OOP)是编程领域中的一个重要概念,特别是在Web开发中,JavaScript作为客户端的主要脚本语言,其OOP能力对于构建复杂、可维护的应用至关重要。@juandc 在 @Platzi 的课程中深入探讨了这个...

    prototype_oop_javascript_ruby_prototype_

    在JavaScript中,原型是实现OOP的一个关键机制,而在Ruby中,虽然使用的是类(Class)作为主要的OOP构造,但仍然可以找到与JavaScript原型模式相类似的思想。让我们深入了解一下这两个语言中的原型和面向对象编程。 ...

    complete-javascript-course-master.zip

    此外,还将涵盖闭包、作用域、原型链等高级特性,这些是JavaScript中的精髓,也是面试和实际工作中常考的知识点。 函数式编程也是本课程的重要组成部分,学员会接触到高阶函数、柯里化、map、reduce等函数式编程...

    javascript oop开发滑动(slide)菜单控件.docx

    在本篇文章中,我们将探讨如何使用JavaScript面向对象编程(OOP)来开发一个可滑动的菜单控件。该控件能够根据用户的交互(如鼠标悬停)动态展示或隐藏二级菜单项,为用户提供更加友好的导航体验。通过面向对象的设计...

    OOP-PHP-Gallary:通过使用oop techinq创建项目

    **PHP面向对象编程在创建图库项目中的应用** 在现代Web开发中,PHP作为一种服务器端脚本语言,因其灵活性...通过学习和理解这个项目,开发者可以深入理解如何在实际项目中应用面向对象编程思想,提升代码质量和效率。

    Javascript完全自学宝典

    - 面向对象编程(OOP)在JavaScript中的实现。 - 函数式编程(FP)思维模式。 4. **XMPP高级编程——使用JavaScript和jQuery** - **核心知识点**: - XMPP协议的基本原理。 - 如何使用JavaScript和jQuery开发即时...

    悟透JavaScript--《JavaScript真经》

    《JavaScript真经》的描述中,作者通过比喻和故事深入浅出地阐述了JavaScript的核心概念,尤其是数据和代码的关系,以及面向对象编程的思想。 在编程中,数据和代码是两个基本的组成部分。数据代表了程序中的信息,...

    oop-promises-async-await:这是我针对OOP,Promises,AsyncAwait GA课程的仓库

    在"oop-promises-async-await-master"这个压缩包中,我们可以期待找到关于以上知识点的代码示例、讲解文档或者练习题,帮助我们深入理解和掌握JavaScript中的OOP、Promise和Async/Await。通过实践这些内容,可以提升...

    悟透JavaScript.pdf

    - **面向对象编程(OOP)**是一种将数据和代码结合在一起的思想,它极大地简化了编程过程中的复杂度。通过将数据和代码封装在一个对象中,使得原本复杂的程序结构变得清晰有序。 - **对象**:在OOP中,对象是一个...

    JavaScipt-OOP:JavaScript OOP课程作业

    JavaScript面向对象编程(Object-Oriented Programming,OOP)是JavaScript...通过这份“JavaScript OOP课程作业”,学生将有机会实践上述概念,理解JavaScript中面向对象编程的核心思想,并学会如何在实际项目中应用。

    oop-blog

    - **文章**:博客文章可能会深入解释OOP的原理、最佳实践、设计模式,以及如何在实际项目中应用OOP思想。 - **示例代码**:这些代码片段可能会演示如何在不同编程语言(如Java、Python、C#等)中实现OOP概念,同时...

    react-demos-master.zip_DEMO_React_oop_rract

    "react-demos-master.zip_DEMO_React_oop_rract"这个压缩包包含了一系列关于React的示例代码,旨在帮助开发者理解并掌握React的基本用法以及面向对象编程(OOP)在React中的应用。下面将详细介绍React的核心概念、...

    老生常谈javascript的面向对象思想

    在进行JavaScript编程的过程中,面向对象思想一直是一个核心的概念。面向对象编程(OOP)是通过创建对象来模拟现实世界的一种编程范式。在JavaScript中,对象可以通过不同的方法创建和定义。面向对象有三大基本特性...

    Object-Oriented JavaScript

    - **本书贡献**:本书深入探讨了如何利用面向对象的思想编写出高质量的JavaScript代码。通过学习本书,读者不仅可以了解到面向对象的基本概念,还能学会如何将这些概念应用于实际的开发工作中,构建出更加健壮和易于...

Global site tag (gtag.js) - Google Analytics