我们常用的两种编程模式

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.

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

  1. 浅谈JavaScript浮点数及其运算

    原文:浅谈JavaScript浮点数及其运算     JavaScript 只有一种数字类型 Number,而且在Javascript中所有的数字都是以IEEE-754标准格式表示的.浮点数的精度问题 ...

  2. 浅谈javascript函数节流

    浅谈javascript函数节流 什么是函数节流? 函数节流简单的来说就是不想让该函数在很短的时间内连续被调用,比如我们最常见的是窗口缩放的时候,经常会执行一些其他的操作函数,比如发一个ajax请求等 ...

  3. 浅谈JavaScript中的闭包

    浅谈JavaScript中的闭包 在JavaScript中,闭包是指这样一个函数:它有权访问另一个函数作用域中的变量. 创建一个闭包的常用的方式:在一个函数内部创建另一个函数. 比如: functio ...

  4. 浅谈JS面向对象

    浅谈JS面向对象 一 .什么是面向过程 就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了.注重代码的过程部分. 二.什么是面向对象 最先出现在管理学 ...

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

    对于熟悉 C/C++ 或 Java 语言的工程师来说,JavaScript 显得灵活,简单易懂,对代码的格式的要求也相对松散.很容易学习,并运用到自己的代码中.也正因为这样,JavaScript 的编 ...

  6. 浅谈javascript的原型及原型链

    浅谈javascript的原型及原型链 这里,我们列出原型的几个概念,如下: prototype属性 [[prototype]] __proto__ prototype属性 只要创建了一个函数,就会为 ...

  7. 浅谈JavaScript中的null和undefined

    浅谈JavaScript中的null和undefined null null是JavaScript中的关键字,表示一个特殊值,常用来描述"空值". 对null进行typeof类型运 ...

  8. 浅谈JavaScript中的正则表达式(适用初学者观看)

    浅谈JavaScript中的正则表达式 1.什么是正则表达式(RegExp)? 官方定义: 正则表达式是一种特殊的字符串模式,用于匹配一组字符串,就好比用模具做产品,而正则就是这个模具,定义一种规则去 ...

  9. [转载]浅谈JavaScript函数重载

     原文地址:浅谈JavaScript函数重载 作者:ChessZhang 上个星期四下午,接到了网易的视频面试(前端实习生第二轮技术面试).面了一个多小时,自我感觉面试得很糟糕的,因为问到的很多问题都 ...

随机推荐

  1. JavaScript 垃圾回收

    在公司经常会听到大牛们讨论时说道内存泄露神马的,每每都惊羡不已,最近精力主要用在了Web 开发上,读了一下<JavaScript高级程序设计>(书名很唬人,实际作者写的特别好,由浅入深)了 ...

  2. ASP.NET MVC5 ModelBinder

    什么是ModelBinding ASP.NET MVC中,所有的请求最终都会到达某个Controller中的某个Action并由该Action负责具体的处理和响应.为了能够正确处理请求,Action的 ...

  3. .Net语言 APP开发平台——Smobiler学习日志:如何实现离线声音文件上传

    最前面的话:Smobiler是一个在VS环境中使用.Net语言来开发APP的开发平台,也许比Xamarin更方便 一.目标样式 我们要实现上图中的效果,需要如下的操作: 1.从工具栏上的"S ...

  4. MongoDB初识

    参考: MongoDB资料汇总专题:

  5. PHP学习笔记:输入一句话,实现单词倒序输出

    约定:句子以空格为词语分割符号,以句号为结束符号. 实现思路: 用函数explode(separator,string,limit)对字符串进行分割,再对得到的数据最后一个成员分割切掉符号.用一个新的 ...

  6. Android 手机卫士3--设置中心

    1.要点击九宫格中的条目,需要注册点击事件 // 注册九宫格单个条目的点击事件 gv_home.setOnItemClickListener(new OnItemClickListener() { / ...

  7. bootstrap(关于栅格布局)

    栅格系统是通过行(.row)与列(column)的组合一起来创建页面布局的,所以只有列(column)可以作为行(row)的直接子元素,我们所要写的内容可以放在列里(column),不过在行的外层还需 ...

  8. Atitit mac os 版本 新特性 attilax大总结

    Atitit mac os 版本 新特性 attilax大总结 1. Macos概述1 2. 早期2 2.1. Macintosh OS (系统 1.0)  1984年2 2.2. Mac OS 7. ...

  9. Android中的AlertDialog使用示例五(自定义对话框)

    在Android开发中,我们经常会需要在Android界面上弹出一些对话框,比如询问用户或者让用户选择.这些功能我们叫它Android Dialog对话框,AlertDialog实现方法为建造者模式. ...

  10. how2heap分析系列:1_first_fit

    一些基础知识不再赘述,可以自行搜索解决 程序源码first_fit.c #include <stdio.h> #include <stdlib.h> #include < ...