浅谈javascript面向对象

我们常用的两种编程模式

POP--面向过程编程(Process-oriented programming)

面向过程编程是以功能为中心来进行思考和组织的一种编程方法,它强调的是系统的数据被加工和处理的过程,在程序设计中主要以函数或者过程为程序的基本组织 方式,系统功能是由一组相关的过程和函数序列构成。面向过程强调的是功能(加工),数据仅仅作为输入和输出存在。这种过程化的思想是一种很朴素和普遍的思 想和方法,人类很多活动都是这种组织模式,比如工厂生产,企业服务等。面向过程以数据的加工处理过程为主线,忽略了过程的所属、边界和环境,混淆了服务功 能和自我功能(比如人可以砍树,这就是一种服务功能,有输入也有输出;它可以提供给外部,而行走,则是自我功能,没有输入也没有输出),外部环境和内部组 织,以及环境数据和原料性数据之间的区别。从思维上来讲,面向过程更强调细节,忽视了整体性和边界性,但这与现实世界有很大的出入,因为现实世界中,这种过程都不是孤立存在的,而是从属于某个对象,因此,面向过程虽然反映了现实世界的而一个方面(功能),但无法更加形象的模拟或者表示现实世界。比如如下这种写法:

function  A(){

}
function  B(){
   A();
}

感觉互相之间独立存在的

OOP--面向对象编程(Object Oriented Programming)

世界是由一个个对象组成的,因此面向对象的思维方式更加接近现实世界,面向对象编程的组织方式也更加贴近现实世界。面向对象以对象为中心,将对象的内部组织与外部环境区分开来,将表征对象的内部属性数据与外部隔离开来,其行为与属性构成一个整体,而系统功能则表现为一系列对象之间的相互作用的序列,能更加 形象的模拟或表达现实世界。在编程组织中,对象的属性与方法不再像面向过程那样分开存放,而是视为一个整体(程序的最终实现其实还是分离的,但这仅仅是物 理实现上的,不影响将对象的这两个部分视为一个整体),因此具有更好的封装性和安全性(表征内部的属性数据需要通过对象的提供的方法来访问)。面向对象强 调的是整体性,因此面向对象与面向过程在很多方面是可以互补的。同时由于对象继承和多态技术的引入,使得面向对象具有更强、更简洁的对现实世界的表达能 力。从而增强了编程的组织性,重用性和灵活性。比如如下这种写法:

 var   obj={
  default:{},
  config:{},
  init:function(){
    this.A();
    this.B();
  },
  A:function(){
      this.config.name=’A’;
  },
  B:function(){
    this.config.name=’B’;
  }
}

这种看起来就有点OO的感觉了,把属性和方法封装在一个对象里面。面向对象的开发模式是逐渐流行起来,且被开发者们广泛推广的模式。

Javascript是一门基于对象的语言,但它不是一种真正的面向对象编程(OOP)语言,对象的属性都是以键值对的形式存在的,就是平时我们所说的数据字典。把对象的属性和方法封装在一个对象里面,一般通过四种方式:原始对象,构造函数,原型模式,构造函数和原型混合模式。我个人认为面向对象的写法让系统更具有可维护性,可扩展性,可重用性,还有可配置性,功能模块也让人感觉一目了然。

下面来讲一下关于javascript对应的OOP的封装,继承,多态三大特性

  • 对象的封装  

(1)对象字面量或者实例化对象模式

var Obj = {
    Id: ‘‘,
    Width: ‘‘,
    Height: ‘‘,
    init: function() {

    },
    eventsBind: function() {

    },
    renderView: function() {

    }
}

或者

Var  obj=new  Object();

Obj.id=’’;….

Obj. renderView….

这种封装方式比较简单, 最常用的一种模式,简洁明了,适用于简单的封装.这两种写法,推荐字面量的方式。

(2) 构造函数模式

function MyPlugin(name, pwd) {
    this.name = name;
    this.pwd = pwd;
    this.Init = function() {

    };
    this.renderView = function() {

    };
    this.bindEvent = function() {

    }
}

这种方式和C#的构造函数方式类似,每次实例化,所有的元素和方法都被重新创建,重新分配内存,互不影响 ,缺点在于实例化时公有的方法指向不同的地址,造成不必要的浪费,性能欠佳 ,方法应该共享才对,下面的混合模式会讲到。

(3)原型prototype

var MyPlugin = function(){

}
MyPlugin.prototype = {
    obj: {
        name: ’aaaaa’
    },
    Init: function() {

    },
    renderView: function() {

    },
    bindEvent: function() {

    }
}

这种方式的特点是所有的在原型链上的方法都是共享的,并且指向同一个地址。这里需要注意,如果原型链上面一个属性对应的是object对象会有一个问题,就是在一个实例对象里面给这个对象的属性赋值会影响另一个实例对象.

var  a=new MyPlugin();

var  b= new MyPlugin();

a.obj.name=’bbbbbbbb’

这样在b中的obj对象的name值会被改变。原因是这里的obj是引用类型,a.obj和b.obj指向的是同一个地址,如果是值类型则不会存在这样的问题

(4)构造函数和原型混合模式

这种模式的意义在于实例化的时候保持属性的相互独立,只共享方法.在做封装的时候推荐使用这种方式.刚才我们所说的构造函数的缺点和原型模式的缺点在这里得到改善。

var MyPlugin = function(name) {
    this.name = name;
}

MyPlugin.prototype = {
    Show: function(){
        Console.log(this.name);
    }
}

(5) 其他写法

var MyPlugin = function(config) {
    var fn1 = function() {
    }
    var fn2 = function() {
    }
    return {
        test1: fn1,
        test2: fn2
    }
}

或者

var MyPlugin = function(config) {
    var obj = new Object();
    obj.fn1 = function() {
    }
    obj.fn2 = function() {
    }
    return obj;
}
    

刚才我们提到构造函数模式实例化之后对象的方法地址指向不一样,而原型模式,地址指向一致的说法。

我们来看一下:

var   funcDemo=function (name) {

}
funcDemo.prototype.init=function(){

}
var  a=new  funcDemo(‘aaa‘);
var  b=new  funcDemo(‘bbb‘);
console.log(a.init===b.init);

输出结果是true.

再来看看构造函数:

var   funcDemo=function (name) {
     this. Init=function(){

     }

 }
var  a=new  funcDemo(‘aaa‘);

var  b=new  funcDemo(‘bbb‘);

console.log(a.init===b.init);

输出结果是false.

  •  对象的继承性

1.call ,apply

var funcA = function() {
    this.show = function() {
        console.log(‘funcA‘);
    }
}
var funcB = function() {
    funcA.call(this);
}
var b = new funcB();
b.show();

在这里 funcA.call(this);这句相当于是在funB的内部里面执行了

this.show=function(){

console.log(‘funcA‘);

}

而当前的作用域在funcB内部,this指向的是funB的实例化对象,也就是把show方法赋值给了funcB的实例化对象

有一点需要注意,如果是直接执行funcB(),那么当前作用域就是window了,相当于把show方法赋值给了window。等同于

window.show==function(){
     console.log(‘funcA‘);
}

2.原型继承

var funcA = function() {
    this.show = function() {
        console.log(‘funcA‘);
    }
}
var funcB = function() {
}
funcB.prototype = new funcA();
var b = new funcB();
b.show();

这一句  funcB.prototype=new  funcA();

相当于把funB的原型指向了funcA的实例

等同于

funcB. Prototype={
  Show:function(){
     console.log(‘funcA‘);
 }
}

我们可以写一个函数来实现继承

var extend = function(fn, newfn) {
var F = function () { };
F.prototype = fn.prototype;
newfn.prototype = new F();
newfn.prototype.constructor = newfn;
newfn.prototype.superClass =fn.prototype

}

3.属性拷贝

我们先实现属性拷贝的代码:

var DeepCopy = function(newobj, obj) {
    for(var prop in obj) {
        if(obj.hasOwnProperty(prop))
        {
            var item = obj[prop];
            if(Object.prototype.toString.call(item) == ‘[object Object]‘)
            {
                newobj[prop] = {};
                arguments.callee(newobj[prop], item);
            }
            else if(Object.prototype.toString.call(item) == ‘[object Array]‘)
            {
                newobj[prop] = [];
                arguments.callee(newobj[prop], item);
            }
            else
                newobj[prop] = item;
        }
    }
    return newobj;
}

然后将A对象里的属性赋给B对象 :

var A = {
    obj: {
        name: ‘AAAA‘
    },
    Arr: [
        {
            name: ‘AAAA‘
        },
        {
            name: ‘BBBB‘
        }
    ]
}
var B = {
    name: ’BBBBBBBBBB’
}
DeepCopy(B, A)

  • 对象的多态性

和其他语言一样  ,先定义一个基类,js不存在类的概念,这里我只是类比的说法.

var   baseClass=function(){
         this.init=function(){
               this.test.apply(this,arguments);
         }
}

这里执行init其实是执行了子类的test方法

我们再定义A类,B类

var  A=function(){
         this.test=function(){
                   alert(‘AAAAAAAAAA‘);
         }
}
var  B=function(){
         this.test=function(){
                   alert(‘BBBBBBBBBBBBB‘);
         }
}

然后将A类,B类的原型指向baseClass的实例,就是我们刚才说的原型继承

  A.prototype=new baseClass();
  B.prototype=new baseClass();

最后我们实例化

 var  a=new  A();
 a.init();
 var  b=new  B();
 b.init();

分别输出‘AAAAAAAAAA‘,‘BBBBBBBBBBBBB‘

我们所实现的js这种多态和强类型语言的多态感觉有所不同,显得不那么直观,因为强类型的语言大都是通过抽象类或者接口声明方法,然后通过子类实现,调用方法的时候其实是实例化抽象类或者接口,指向子类对象的实例。而我们这里的实现实际上是通过父类声明方法调用子类对父类声明方法的实现。

Js 面向对象的这部分东西我也是大致的讲了一下,讲解的不恰当或者不完善的地方,还请详细指出。如果有兴趣交流学习,请看最上角,加入我的qq技术群207058575.

时间: 2024-10-29 19:05:37

浅谈javascript面向对象的相关文章

《浅谈JavaScript系列》系列技术文章整理收藏

<浅谈JavaScript系列>系列技术文章整理收藏 1浅谈JavaScript中面向对象技术的模拟 2浅谈javascript函数劫持[转自xfocus]第1/3页 3浅谈javascript 面向对象编程 4老鱼 浅谈javascript面向对象编程 5浅谈javascript的数据类型检测 6浅谈Javascript嵌套函数及闭包 7根据一段代码浅谈Javascript闭包 8浅谈JavaScript编程语言的编码规范 9浅谈Javascript面向对象编程 10浅谈JavaScript

浅谈 JavaScript 编程语言的编码规范

对于熟悉 C/C++ 或 Java 语言的工程师来说,JavaScript 显得灵活,简单易懂,对代码的格式的要求也相对松散.很容易学习,并运用到自己的代码中.也正因为这样,JavaScript 的编码规范也往往被轻视,开发过程中修修补补,最终也就演变成为后续维护人员的恶梦.软件存在的长期价值直接与编码的质量成比例.编码规范能帮助我们降低编程中不必要的麻烦.而 JavaScript 代码是直接发送给客户浏览器的,直接与客户见面,编码的质量更应该受到关注. 本文浅谈 JavaScript 编程中关

浅谈javascript单体【读javascript设计模式第五章节单体有感】

单体,整个运行环境就独有一份,最简单的一种单体就是一个把所有属性和方法都集中在一起的对象,区别于一般的字面量对象,一般字面量对象是对一个物体的描述,集合该物体所具有的一些属性和方法,而单体则包含更多的些逻辑在里面,单体的好处有,划分命名空间,如果用来作为网页包装器,可以使得页面所有变量都封装在一个对象里,大幅度减小网页里的全局变量, 代码如: common.js (function(wz){ $.extend({ init:function(){ var self = this; this.bi

浅谈javascript继承【读javascript设计模式第四章节继承有感】

javascript继承,无任是类式继承,原型式继承还是渗元式继承都是通过不同方法去围绕着prototype转,简单分析下三种不同继承方法是如何围绕prototype转的 一:类似继承,先上关键代码 function extend(subClass,supClass){ var fn = function(){}; fn.prototype = supClass.prototype; subClass.prototype = new fn(); subClass.prototype.constr

浅谈javascript函数劫持

http://www.xfocus.net/articles/200712/963.html 浅谈javascript函数劫持 文章提交:hkluoluo (luoluonet_at_hotmail.com) by luoluo on 2007-11-30 luoluonet_at_yahoo.cn http://www.ph4nt0m.org 一.概述 javascript函数劫持,也就是老外提到的javascript hijacking技术.最早还是和剑心同学讨论问题时偶然看到的一段代码,大

浅谈JavaScript中的原型模式

在JavaScript中创建对象由很多种方式,如工厂模式.构造函数模式.原型模式等: <pre name="code" class="html">//工厂模式 function createPerson(name,age,job) { var o = new Object; o.name = name; o.age = age; o.job = job; o.sayName = function() { alert(this.name); } retur

浅谈javascript的原型及原型链

浅谈javascript的原型及原型链 这里,我们列出原型的几个概念,如下: prototype属性 [[prototype]] __proto__ prototype属性 只要创建了一个函数,就会为该函数创建一个prototype属性,指向该函数的原型对象.实例对象是不会拥有该属性的.默认情况下,该原型对象也会获得一个constructor属性,该属性包含一个指针,指向prototype属性所在的函数. Person.prototype.constructor===Person [[proto

浅谈JavaScript运行机制

浅谈JavaScript运行机制 ? 想要了解一门语言,最好的办法就是了解它的运行机制.掌握了运行机制,能够让我们在开发中少走许多弯路,写出高质量的代码.本文简单介绍什么是JavaScript的运行机制,给刚刚接触JavaScript的小白一个初步的了解,为将来打好基础. 一.JavaScript 代码运行分两个阶段: 1.预解析---把所有的函数定义提前,所有的变量声明提前,变量的赋值不提前 2.执行---从上到下执行(按照js运行机制) 二.JavaScript运行机制的特点 1.JavaS

浅谈JavaScript的面向对象和它的封装、继承、多态

写在前面 既然是浅谈,就不会从原理上深度分析,只是帮助我们更好地理解... 面向对象与面向过程 面向对象和面向过程是两种不同的编程思想,刚开始接触编程的时候,我们大都是从面向过程起步的,毕竟像我一样,大家接触的第一门计算机语言大概率都是C语言,C语言就是一门典型的面向过程的计算机语言.面向过程主要是以动词为主,解决问题的方式是按照顺序一步一步调用不同的函数.面向对象是以名词为主,将问题抽象出具体的对象,而这个对象有自己的属性和方法,在解决问题的时候,是将不同的对象组合在一起使用. //面向过程装