JavaScript 面向对象编程 基础_js面向对象_脚本之家

 澳门新葡350vip最新网站     |      2019-12-25 09:57

本文承接上一篇JavaScript面向对象编程基础。 上篇说过,JavaScript没有类的概念,需要通过函数来实现类的定义。先通过一个例子说明: 复制代码 代码如下: function myClass() { var id = 1; var name = "johnson"; //properties this.ID = id; this.Name = name; //method this.showMessage = function() { alert("ID: " + this.ID + ", Name: " + this.Name); } } var obj1 = new myClass(); var obj2 = new myClass(); function的定义实际上相当于类的构造函数,最后两句是创建这个类的实例。先分析第一句:var obj1 = new myClass(); 当用new创建类的实例时,解释器首先会创建一个空的对象。然后运行这个myClass函数,并将this指针指向这个类的实例。当碰到this.ID = id;和this.Name = name;及this.showMessage = function(){...}时,便会创建这两个属性,和这个方法,并把变量id,name的值一级函数的定义赋给这两个属性及这个函数对象。这个过程相当于初始化这个对象,类似于C# 中的构造函数。最后new返回这个对象。再看第二句:var obj2 = new myClass(); 执行过程与上一句代码相同,即创建一个空对象,然后执行myClass这个函数,定义两个属性和一个方法。 从上面的分析中可以看到,上面这种实现类的方式,即在函数的定义中定义类的属性方法。存在着弊端。如果需要创建两个或更多这个类的实例时,上文是两个,这些属性会被重复的创建多次。 那么如何避免这种情况呢?上一篇中也曾提到过用prototype。prototype和它的名字一样是一个原型,每一个function都有一个子对象prototype,它其实表示这个function对象的成员的集合,由于这里我们使用function实现类的,所以可以说prototype其实就是便是类的成员的集合。prototype定义的属性和方法执行在函数的构造体执行之前,所以当new一个对象之前,其实prototype的成员已经执行过了。先看一个例子: 复制代码 代码如下: function myClass() { //构造函数 } myClass.prototype = { ID: 1, Name: "johnson", showMessage: function() { alert("ID: " + this.ID + ", Name: " + this.Name); } } var obj1 = new myClass(); var obj2 = new myClass(); 类的结构还是和前面的例子相同,只不过这里是利用了prototype来实现。还是先看最后两句,前面说过,prototype是执行在函数构造体之前,即执行到var obj1 = new myClass();之前,这个类已经有了ID,Name属性和showMessage方法。执行者一句时执行过程如下,注意和前一个例子比较:首先还是创建一个空的对象,并把this指针指向这个对象。然后将函数的prototype对象的所有成员都赋给这个对象。然后执行函数体。最后new返回这个对象。执行下一句时:同样执行此过程,不会重复创建这些成员。 上面的代码还只是一个例子,在实际的项目中,可能出现的是类中有大量的成员,同时可能需要创建大量的实例。这是prototype就会显示其优越性了。另外上面的代码中使用了大括号语法定义了prototype的成员,这样看起来代码更清晰。这是一种比较推荐的类的设计模式。当然在众多的项目中,可能还会发现更好的模式,我们也希望能有更优化的JavaScript的编程模式不断推陈出新,也希望随着时间的推移,各主流浏览器也对JavaScript的解析都标准,统一。 上面说过prototype定义的成员是发生在构造体之前,可以证明一下,在上面的例子中,构造体是空的,在构造函数中加入一句alert;,当执行到var obj1 = new myClass();时,会看到弹出对话框,显示正确的属性值。 写了这段文字之后承蒙多为兄弟的点评,收获匪浅。对上面的例子进一步讨论,如下代码: 复制代码 代码如下: function subClass(){ } subClass.prototype = { Name: "sub" } function myClass() { //构造函数 } myClass.prototype = { ID: 1, Name: "johnson", SubObj: new subClass(), showMessage: function() { alert("ID: " + this.ID + ", Name: " + this.Name + "SubObj.Name:" + this.SubObj.Name); } } var obj1 = new myClass(); obj1.SubObj.Name = "XXX"; obj1.showMessage(); var obj2 = new myClass; 这里在myClass中定义了一个引用类型,其类型是我们自定义的一个subClass类,这个子类中有一个Name属性。由于prototype对象是共享的,按照我们上面的分析:在执行var obj1 = new myClass();时,会把myClass的prototype中的成员复制给这个obj1实例。但这里SubObj是一个引用类型,在执行到var obj2 = new myClass();时,prototype中的ID,Name成员会复制到obj2中,但SubObj这个属性不会复制过去,而是引用了prototype中的SubObj,所以因为上一句修改了obj1.Subobj.Name的值,所以在用new生成obj2实例时,引用到了修改后的值。 所以借用prototype定义类时,依然需要将属性定义在构造体中,而将方法定义在该构造体的原型上。如下: 复制代码 代码如下: function myClass { this.ID = id; this.Name = name; } myClass.prototype = { showMessage: function() { alert("ID: " + this.ID + ", Name: " + this.Name); }, showMessage2: function; } } var obj1 = new myClass; obj1.showMessage(); obj1.Name="John"; obj1.showMessage(); var obj2 = new myClass; obj2.showMessage(); 关于私有成员,共有成员以及静态成员,类的继承,抽象类,虚方法,类的反射等实现方法,以后还会坚持写下去。不过我觉得需要说一下的是,我打算写的是JavaScript面向对象的基础实现,如果需要深入的学习建议参考李战老哥的“甘露模型”。

1. 用JavaScript实现类 JavaScritpt没有专门的机制实现类,这里是借助它的函数允许嵌套的机制来实现类的。一个函数可以包含变量,又可以包含其它函数,这样,变量可以作为属性,内部的函数就可以作为成员方法了。因此外层函数本身就可以作为一个类了。如下: 复制代码 代码如下: function myClass() { //此处相当于构造函数 } 这里 myClass就是一个类。其实可以把它看成类的构造函数。至于非构造函数的部分,以后会详细描述。 2. 如何获得一个类的实例 实现了类就应该可以获得类的实例,JavaScript提供了一个方法可以获得对象实例。即 new操作符。其实JavaScript中,类和函数是同一个概念,当用new操作一个函数时就返回一个对象。如下: var obj1 = new myClass(); 3. 对象的成员的引用 在JavaScript中引用一个类的属性或方法的方法有以下三种。 1> 点号操作符 这是一种最普遍的引用方式,就不累赘。即如下形式: 对象名.属性名; 对象名.方法名; 2> 方括号引用 JavaScript中允许用方括号引用对象的成员。如下: 对象名["属性名"]; 对象名["方法名"]; 这里方括号内是代表属性或方法名的字符串,不一定是字符串常量。也可以使用变量。这样就可以使用变量传递属性或方法名。为编程带来了方便。在某些情况下,代码中不能确定要调用那个属性或方法时,就可以采用这种方式。否则,如果使用点号操作符,还需要使用条件判断来调用属性或方法。 另外,使用方括号引用的属性和方法名还可以以数字开头,或者出现空格,而使用点号引用的属性和方法名则遵循标示符的规则。但一般不提倡使用非标示符的命名方法。 3> 使用eval函数 如果不希望使用变量传递变量或方法名,又不想使用条件判断,那么eval函数是一个好的选择。eval接收一个字符串类型的参数,然后将这个字符串作为代码在上下文中执行,返回执行的结果。这里正是利用了eval的这一功能。如下: alert(eval("对象名." + element.value)); 4. 对对象属性,方法的添加、修改和删除操作 JavaScript中,在生成对象之后还可以为对象动态添加、修改和删除属性和方法,这与其它面向对象的语言是不同的。 1> 添加属性和方法 先创建一个对象,空对象创建后没有任何属性和方法,然而我们可以在代码中创建。 复制代码 代码如下: var obj1 = new Object(); //添加属性 obj1.ID = 1; obj1.Name = "johnson"; //添加方法 obj1.showMessage = function() { alert("ID: " + this.ID + ", Name: " + this.Name); } 2> 修改属性与方法 与添加属性和方法类似,例如接着上面的例子: 复制代码 代码如下: // 修改属性 obj1.ID = 2; obj1.Name = "Amanda"; // 修改方法 obj1.showMessage = function() { alert; } 3> 删除属性与方法 直接将要删除的属性或方法赋值为undefined即可: 复制代码 代码如下: obj1.ID = 1; obj1.Name = undefined; obj1.showMessage = undefined; 5. 创建无类型对象。 类似于C#3.0里的Anonymous Types,JavaScript 也可以创建无类型的对象。形式如下: 复制代码 代码如下: var obj1 = {}; var obj2 = { ID: 1, Name: "Johnson", showMessage: function() { alert("ID: " + this.ID

Javascript的重要性 使用率 1、在web应用中,涉及到前端界面编程基本上都要用到javascript语言; 2、Web2.0及Ajax推动了javascript语言。 3、随着大量的c/s应用转向b/s,富客户端技术的不断推广,javascript语言的应用范围还将不断加大; javascript的特点 简单 动态 基于对象 Javascript面向对象概述 Javascript是一种面向对象的动态脚本语言,是一种基于对象和事件驱动并具有安全性能的脚本语言。他具有面向对象语言所特有的各种特性,比如封装、继承及多态等。但对于大多数人说,我们只把javascript做为一个函数式语言,只把他用于一些简单的前端数据输入验证以及实现一些简单的页面动态效果等,我们没能完全把握动态语言的各种特性。 在很多优秀的Ajax框架中,比如ExtJS、JQuery等,大量使用了javascript的面向对象特性,要使用好ext技术,javascript的高级特性,面向对象语言特性是我们必须完全把握的。 Javascript的相关知识 Javascript的发展历程 Javascript的三大组成部分 ECMAScript 语法数据类型语句关键字保留字操作符对象 DOM(Document Object Model) BOM JavaScript灵活特性探讨 1、动态语言的灵性测试 Javascript作为一种动态语言,具有非常灵活的我发,在使用的过程中需要灵活掌握及应用他的动态特性,才会得心应手。 思考下面的输出 复制代码 代码如下: function Animal{ this.name=name; this.age=0; }; var a1=Animal;//输出: var a2=Animal();//输出: var a3=new Animal();//输出: var a4=new Animal;//输出: Javascript中的数据类型 基本数据类型 数字 布尔Boolean 特殊值。 对象类型Object 对象属于复杂的数据类型,对象下面可以包含基本类型、对象、函数等,数组是一种对象类型。对于javascript来说,可以说一切都是对象,包括类!。 var c=new Object(); 1、数字类型 数字类型是所有语言中都存在的基本数据类型,javascript中的数字类型主要包括整型两种,但实质两种类型都是以浮点的形式保存在内存中。数字类型在javascript中一般与数字常量的形式出现在程序中,一般情况下是基于10进制的数据,由0-9这10个数字组成,比如110、150等,而也可以是以0x开头的16进制数据,比如0xff转换成10进制就是255;一些javascript实现还支持8进制数据,也就是以0开头的数据,比如0377 这个八进制数据转换成10进制就是255,即( 3*64 + 7*8 + 7 = 255 )。 2、字符类型 字符串由各种字符、数字及特殊字符串组成,可以在程序中直接使用单引号或双引号来生成字符串常量。字符串中不能有回车符,要在字符串包含回车需要使用转义字符n。下面是一些简单的字符串常量: "" // The empty string: it has zero characters 'testing' "3.14" 'name="myform"' "Wouldn't you prefer O'Reilly's book?" "This stringnhas two lines" "π is the ratio of a circle's circumference to its diameter" 3、布尔Boolean 布尔类型用来表示真或假,在javascript中,当用于布尔运算时,除了0、空字符、null、undefined、NaN等以外的数据都是表示真。 if(0||""||false||null||undefined||NaN)alert; 布尔常量只有false及true,False及True不是常量。 4、对象类型 javascript是基于对象的语言,对象是其核心。 程序流程控制 顺序结构 if条件选择语句 switch选择语句 while循环语句 do while语句 for循环语句 break与continue语句 for...in循环语句 for { 执行语句块 } 复制代码 代码如下:

这两天有个前同事总在问我Javascript面向对象的东西,所以,索性写篇文章让他看去吧,这里这篇文章主要想从一个整体的角度来说明一下Javascript的面向对象的编程。(成文比较仓促,应该有不准确或是有误的地方,请大家批评指正) 另,这篇文章主要基于 ECMAScript 5, 旨在介绍新技术。关于兼容性的东西,请看最后一节。 初探 我们知道Javascript中的变量定义基本如下: 复制代码 代码如下: var name = 'Chen Hao';; var email = 'haoelhotmail.com'; var website = ''; 如果要用对象来写的话,就是下面这个样子: 复制代码 代码如下: var chenhao = { name :'Chen Hao', email : 'haoelhotmail.com', website : '' }; 于是,我就可以这样访问: 复制代码 代码如下: //以成员的方式 chenhao.name; chenhao.email; chenhao.website; //以hash map的方式 chenhao["name"]; chenhao["email"]; chenhao["website"]; 关于函数,我们知道Javascript的函数是这样的: 复制代码 代码如下:var doSomething = function(){ alert; }; 于是,我们可以这么干: 复制代码 代码如下:var sayHello = function(){ var hello = "Hello, I'm "+ this.name

  • "Name: " + this.Name); } } 这里定义了两个无类型的对象,obj1和obj2。其中obj1是一个空对象。obj2包括两个属性ID, Name和一个方法showMessage。每个属性和方法用逗号分割。属性名和其值之间用分号分割。 用这种方式创建属性方法时,也可以用字符串定义属性方法的名字。如: 复制代码 代码如下: var obj2 = { "ID" : 1, "Name": "Johnson" } 6. prototype 每个函数对象都具有一个子对象prototype,因为函数也可以表示类,所以prototype表示一个类的成员的集合。当new 一个对象时,prototype对象的成员都会被实例化成对象的成员。先看一个例子: 复制代码 代码如下: function myClass() { } myClass.prototype.ID = 1; myClass.prototype.Name = "johnson"; myClass.prototype.showMessage = function() { alert("ID: " + this.ID + "Name: " + this.Name); } var obj1 = new myClass; 使用prototype对象创建类有一个好处。如果将所有的成员直接写在类的声明中,如下: 复制代码 代码如下: function myClass() { //添加属性 this.ID = 1; this.Name = "johnson"; //添加方法 this.showMessage = function() { alert("ID: " + this.ID + ", Name: " + this.Name); } } var obj1 = new myClass(); var obj2 = new myClass(); 在上面的代码中,定义了一个类myClass,在类中直接定义了两个属性和一个方法。然后实例化了两个对象,这里的两个属性和一个方法,每创建一次myClass对象都会被创建一次,浪费了内存空间。而用prototype以后就可以解决这个问题,每new一个函数时,其prototype对象的成员都会自动赋给这个对象,当new多个对象时不会重复创建。 由于prototype的初始化发生在函数体执行之前,用以下代码可以证明: 复制代码 代码如下: function myClass() { //此处相当于构造函数 this.ID = 1; this.Name1 = this.Name; this.showMessage(); } myClass.prototype.Name = "johnson"; myClass.prototype.showMessage = function() { alert("ID: " + this.ID + ", Name: " + this.Name); } var obj1 = new myClass(); 执行以上代码可以发现当new这个类型的对象时,即弹出了对话框。 最后只得一提的是,prototype有一个方法,在面向对象的设计中用得到。即:constructor属性,是对构造函数的调用,这里的构造函数即上文提到的类的声明里的代码。如: 复制代码 代码如下: function myClass() { //此处相当于构造函数 alert("this is in constructor"); } myClass.prototype.constructor(); var obj1 = new myClass(); 执行以上代码你会发现对话框弹出了两次。由此可见,prototype可专门用于设计类的成员,实际上在JavaScript面向对象的设计中,很多时候都会用到prototype。

var as={id:5,name:'test'}; for { output += x+"="+as[x]; } alert; 逻辑运算符 && 逻辑与,当左右两边操作数都为true时,返回值为true,否则返回false。 逻辑或,当左右两边操作数都为false时,返回其中第一个不为false的值或者false。 ! 逻辑非,当操作数为true时,返回值为false,否则返回true。 注意: 在逻辑运算中,0、""、false、null、undefined、NaN均表示false。 函数的定义及调用 定义一个函数的格式如下: function 函数名 { 程序代码 return 表达式; } 复制代码 代码如下:

  • ", my email is: " + this.email + ", my website is: " + this.website; alert; }; //直接赋值,这里很像C/C++的函数指针 chenhao.Hello = sayHello; chenhao.Hello(); 相信这些东西都比较简单,大家都明白了。 可以看到javascript对象函数是直接声明,直接赋值,直接就用了。runtime的动态语言。 还有一种比较规范的写法是: 复制代码 代码如下: //我们可以看到, 其用function来做class。 var Person = function{ this.name = name; this.email = email; this.website = website; this.sayHello = function(){ var hello = "Hello, I'm "+ this.name + ", n" + "my email is: " + this.email + ", n" + "my website is: " + this.website; alert; }; }; var chenhao = new Person("Chen Hao", "haoel@hotmail.com", ""); chenhao.sayHello(); 顺便说一下,要删除对象的属性,很简单: 1 delete chenhao['email'] 上面的这些例子,我们可以看到这样几点: Javascript的数据和成员封装很简单。没有类完全是对象操作。纯动态! Javascript function中的this指针很关键,如果没有的话,那就是局部变量或局部函数。 Javascript对象成员函数可以在使用时临时声明,并把一个全局函数直接赋过去就好了。 Javascript的成员函数可以在实例上进行修改,也就是说不同实例相同函数名的行为不一定一样。 属性配置 – Object.defineProperty 先看下面的代码: 复制代码 代码如下://创建对象 var chenhao = Object.create; //设置一个属性 Object.defineProperty( chenhao, 'name', { value: 'Chen Hao', writable: true, configurable: true, enumerable: true }); //设置多个属性 Object.defineProperties( chenhao, { 'email' : { value: 'haoel@hotmail.com', writable: true, configurable: true, enumerable: true }, 'website': { value: '', writable: true, configurable: true, enumerable: true } } ); 下面就说说这些属性配置是什么意思。 writable:这个属性的值是否可以改。 configurable:这个属性的配置是否可以改。 enumerable:这个属性是否能在for…in循环中遍历出来或在Object.keys中列举出来。 value:属性值。 get:get和set访问器。 Get/Set 访问器 关于get/set访问器,它的意思就是用get/set来取代value,示例如下: 复制代码 代码如下:var age = 0; Object.defineProperty( chenhao, 'age', { get: function() {return age+1;}, set: function {age = value;} enumerable : true, configurable : true } ); chenhao.age = 100; //调用set alert; //调用get 输出101; 我们再看一个更为实用的例子——利用已有的属性通过get和set构造新的属性: 复制代码 代码如下: Object.defineProperty( chenhao, 'birth_year', { get: function() { var d = new Date(); var y = d.getFullYear(); return ; }, set: function { var d = new Date(); var y = d.getFullYear(); this.age = y - year; } } ); alert; chenhao.birth_year = 2000; alert; 这样做好像有点麻烦,你说,我为什么不写成下面这个样子: 复制代码 代码如下:var chenhao = { name: "Chen Hao", email: "haoel@hotmail.com", website: "", age: 100, get birth_year() { var d = new Date(); var y = d.getFullYear(); return ; }, set birth_year { var d = new Date(); var y = d.getFullYear(); this.age = y - year; } }; alert; chenhao.birth_year = 2000; alert; 是的,你的确可以这样的,不过通过defineProperty设置如 writable,configurable,enumerable 等这类的属性配置。 2)动态地为一个对象加属性。比如:一些HTML的DOM对像。 查看对象属性配置 如果查看并管理对象的这些配置,下面有个程序可以输出对象的属性和配置等东西: 复制代码 代码如下: //列出对象的属性. function listProperties { var newLine = "
    "; var names = Object.getOwnPropertyNames; for (var i = 0; i < names.length; i++) { var prop = names[i]; document.write; // 列出对象的属性配置动用getOwnPropertyDescriptor函数。 var descriptor = Object.getOwnPropertyDescriptor; for (var attr in descriptor) { document.write("..." + attr + ': ' + descriptor[attr]); document.write; } document.write; } } listProperties; call,apply, bind 和 this 关于Javascript的this指针,和C++/Java很类似。 我们来看个示例: 复制代码 代码如下:function print{ document.write(this.value + ' - ' + text+ '
    '); } var a = {value: 10, print : print}; var b = {value: 20, print : print}; print;// this => global, output "undefined - hello" a.print;// this => a, output "10 - a" b.print; // this => b, output "20 - b" a['print']; // this => a, output "10 - a" 我们再来看看call 和 apply,这两个函数的差别就是参数的样子不一样,另一个就是性能不一样,apply的性能要差很多。(关于性能,可到 JSPerf 上去跑跑看看) 复制代码 代码如下:print.call; // this => a, output "10 - a" print.call; // this => b, output "20 - b" print.apply; // this => a, output "10 - a" print.apply; // this => b, output "20 - b" 但是在bind后,this指针,可能会有不一样,但是因为Javascript是动态的。如下面的示例 复制代码 代码如下:var p = print.bind; // this => a, output "10 - a" p.call; // this => a, output "10 - b" p.apply; // this => a, output "10 - b" 继承 和 重载 通过上面的那些示例,我们可以通过Object.create()来实际继承,请看下面的代码,Student继承于Object。 复制代码 代码如下:var Person = Object.create; Object.defineProperties ( Person, { 'name' : { value: 'Chen Hao'}, 'email' : { value : 'haoel@hotmail.com'}, 'website': { value: ' } ); Person.sayHello = function () { var hello = "

undefined alert; 对函数进行调用的几种方式: 函数名(传递给函数的参数1,传递给函数的参数2,….) 变量 = 函数名(传递给函数的参数1,传递给函数的参数2,….) 对于有返回值的函数调用,也可以在程序中直接使用返回的结果,例如:alert; 不指定任何函数值的函数,返回undefined。 函数的参数可变性 复制代码 代码如下:

Hello, I am "+ this.name + ",
" + "my email is: " + this.email + ",
" + "my website is: " + this.website; document.write; } var Student = Object.create; Student.no = "1234567"; //学号 Student.dept = "Computer Science"; //系 //使用Person的属性 document.write(Student.name + ' ' + Student.email + ' ' + Student.website +'
'); //使用Person的方法 Student.sayHello(); //重载SayHello方法 Student.sayHello = function { var hello = "

最多255个。通过函数对象的length可以返回函数希望提供的参数个数。 函数参数的可变性 function addalertalert; else alert; } arguments Arguments是一个类似数组但不是数组的对象,说它类似数组是因为其具有数组一样的访问性质及方式,可以由arguments[n]来访问对应的单个参数的值,并拥有数组长度属性length。 如何写一个方法,能实现任意多个数的求和? alert;//输出6 alert;//输出1700 使用Function类创建函数 创建动态函数的基本语法格式: var varName = new Function(argument1,...,lastArgument); 说明: 所有的参数都必须是字符串型的,最后的参数必须是这个动态函数的功能程序代码。 例子: 复制代码 代码如下:

Hello, I am "+ this.name + ",
" + "my email is: " + this.email + ",
" + "my website is: " + this.website + ",
" + "my student no is: " + this. no + ",
" + "my departent is: " + this. dept; document.write; } //再次调用 Student.sayHello(); //查看Student的属性(只有 no 、 dept 和 重载了的sayHello) document.write('

上一篇:JavaScript 继承详解_js面向对象_脚本之家 下一篇:没有了