浅谈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.
浅谈javascript面向对象的更多相关文章
- 浅谈JavaScript浮点数及其运算
原文:浅谈JavaScript浮点数及其运算 JavaScript 只有一种数字类型 Number,而且在Javascript中所有的数字都是以IEEE-754标准格式表示的.浮点数的精度问题 ...
- 浅谈javascript函数节流
浅谈javascript函数节流 什么是函数节流? 函数节流简单的来说就是不想让该函数在很短的时间内连续被调用,比如我们最常见的是窗口缩放的时候,经常会执行一些其他的操作函数,比如发一个ajax请求等 ...
- 浅谈JavaScript中的闭包
浅谈JavaScript中的闭包 在JavaScript中,闭包是指这样一个函数:它有权访问另一个函数作用域中的变量. 创建一个闭包的常用的方式:在一个函数内部创建另一个函数. 比如: functio ...
- 浅谈JS面向对象
浅谈JS面向对象 一 .什么是面向过程 就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了.注重代码的过程部分. 二.什么是面向对象 最先出现在管理学 ...
- 浅谈 JavaScript 编程语言的编码规范
对于熟悉 C/C++ 或 Java 语言的工程师来说,JavaScript 显得灵活,简单易懂,对代码的格式的要求也相对松散.很容易学习,并运用到自己的代码中.也正因为这样,JavaScript 的编 ...
- 浅谈javascript的原型及原型链
浅谈javascript的原型及原型链 这里,我们列出原型的几个概念,如下: prototype属性 [[prototype]] __proto__ prototype属性 只要创建了一个函数,就会为 ...
- 浅谈JavaScript中的null和undefined
浅谈JavaScript中的null和undefined null null是JavaScript中的关键字,表示一个特殊值,常用来描述"空值". 对null进行typeof类型运 ...
- 浅谈JavaScript中的正则表达式(适用初学者观看)
浅谈JavaScript中的正则表达式 1.什么是正则表达式(RegExp)? 官方定义: 正则表达式是一种特殊的字符串模式,用于匹配一组字符串,就好比用模具做产品,而正则就是这个模具,定义一种规则去 ...
- [转载]浅谈JavaScript函数重载
原文地址:浅谈JavaScript函数重载 作者:ChessZhang 上个星期四下午,接到了网易的视频面试(前端实习生第二轮技术面试).面了一个多小时,自我感觉面试得很糟糕的,因为问到的很多问题都 ...
随机推荐
- HTML5 网络拓扑图性能优化
HTML5 中的 Canvas 对文本的渲染(fillText,strokeText)性能都不太好,比如设置字体(font).文本旋转(rotation),如果绘制较多的文本时,一些交互操作会手动很大 ...
- Python黑帽编程 3.4 跨越VLAN
Python黑帽编程 3.4 跨域VLAN VLAN(Virtual Local Area Network),是基于以太网交互技术构建的虚拟网络,既可以将同一物理网络划分成多个VALN,也可以跨越物理 ...
- asp.net core 依赖注入问题
最近.net core可以跨平台了,这是一个伟大的事情,为了可以赶上两年以后的跨平台部署大潮,我也加入到了学习之列.今天研究的是依赖注入,但是我发现一个问题,困扰我很久,现在我贴出来,希望可以有人帮忙 ...
- 福利到!Rafy(原OEA)领域实体框架 2.22.2067 发布!
距离“上次框架完整发布”已经过去了一年半了,应群中的朋友要求,决定在国庆放假之际,把最新的框架发布出来,并把帮助文档整理出来,这样可以方便大家快速上手. 发布内容 注意,本次发布,只包含 Rafy ...
- ASP.NET用QQ,网易发送邮件以及添加附件
教程:ASP.NET用QQ,网易发送邮件以及添加附件 这是我用QQ邮箱出现的异常: 命令顺序不正确. 服务器响应为:Error: need EHLO and AUTH first !无法从传输连接中读 ...
- Atitit.ide技术原理与实践attilax总结
Atitit.ide技术原理与实践attilax总结 1.1. 语法着色1 1.2. 智能提示1 1.3. 类成员outline..func list1 1.4. 类型推导(type inferenc ...
- Workflow笔记3——BookMark和持久化
BookMark 我们在平时的工作流使用中,并不是直接这样一气呵成将整个工作流直接走完的,通常一个流程到了某一个节点,该流程节点的操作人,可能并不会马上去处理该流程,而只有当处理人处理了该流程,流程才 ...
- CRM 2013 相关下载 / 2013-10-11
CRM 2013的安装文件,软件开发工具包(Sdk)以及实施指南,在微软官方网站已经有下载了. 具体地址如下: Name Url 发布日期 语言版本 说明 CRM Server htt ...
- iOS:frame访问、设置简化
看到一些程序都有这种写法,也不知道原创者是谁了.先在博客保存下. 在.m文件 #import "UIView+MyFrameCategory.h" @implementation ...
- Json生成与解析
JSON常用与服务器进行数据交互,JSON中"{}"表示JSONObject,"[]"表示JSONArray 如下json数据: {"singers& ...