SQL Server优化50法
虽然查询速度慢的原因很多,但是如果通过一定的优化,也可以使查询问题得到一定程度的解决。 查询速度慢的原因很多,常见如下几种: 没有索引或者没有用到索引(这是查询慢最常见的问题,是程序设计的缺陷) I/O吞吐量小,形成了瓶颈效应。 没有创建计算列导致查询不优化。 内存不足 网络速度慢 查询出的数据量过大(可以采用多次查询,其他的方法降低数据量) 锁或者死锁(这也是查询慢最常见的问题,是程序设计的缺陷) sp_lock,sp_who,活动的用户查看,原因是读写竞争资源。 返回了不必要的行和列 查询语句不好,没有优化 可以通过如下方法来优化查询 : 把数据、日志、索引放到不同的I/O设备上,增加读取速度,以前可以将Tempdb应放在RAID0上,SQL2000不在支持。数据量(尺寸)越大,提高I/O越重要. 纵向、横向分割表,减少表的尺寸(sp_spaceuse) 升级硬件 根据查询条件,建立索引、优化索引、优化访问方式,限制结果集的数据量。注意填充因子要适当(最好是使用默认值0)。索引应该尽量小,使用字节数小的列建索引好(参照索引的创建),不要对有限的几个值的字段建单一索引如性别字段 提高网速; 扩大服务器的内存,Windows 2000和SQL server 2000能支持4-8G的内存。配置虚拟内存:虚拟内存大小应基于计算机上并发运行的服务进行配置。运行 Microsoft SQL Server 2000 时,可考虑将虚拟内存大小设置为计算机中安装的物理内存的 1.5 倍。如果另外安装了全文检索功能,并打算运行 Microsoft 搜索服务以便执行全文索引和查询,可考虑:将虚拟内存大小配置为至少是计算机中安装的物理内存的 3 倍。将 SQL Server max server memory 服务器配置选项配置为物理内存的 1.5 倍(虚拟内存大小设置的一半)。 增加服务器CPU个数;但是必须明白并行处理比串行处理更需要资源例如内存。使用并行还是串行程是MsSQL自动评估选择的。单个任务分解成多个任务,就可以在处理器上运行。例如耽搁查询的排序、连接、扫描和GROUP BY字句同时执行,SQL SERVER根据系统的负载情况决定最优的并行等级,复杂的需要消耗大量的CPU的查询最适合并行处理。但是更新操作UPDATE,INSERT,DELETE还不能并行处理。 如果是使用like进行查询的话,简单的使用index是不行的,但是全文索引耗空间。 like 'a%' 使用索引 like '%a' 不使用索引。用 like '%a%' 查询时,查询耗时和字段值总长度成正比,所以不能用CHAR类型,而是VARCHAR。对于字段的值很长的建全文索引。 DB Server 和APPLication Server分离;OLTP和OLAP分离 分布式分区视图可用于实现数据库服务器联合体。联合体是一组分开管理的服务器,但它们相互协作分担系统的处理负荷。这种通过分区数据形成数据库服务器联合体的机制能够扩大一组服务器,以支持大型的多层 Web 站点的处理需要。有关更多信息,参见设计联合数据库服务器。(参照SQL帮助文件’分区视图') 在实现分区视图之前,必须先水平分区表 在创建成员表后,在每个成员服务器上定义一个分布式分区视图,并且每个视图具有相同的名称。这样,引用分布式分区视图名的查询可以在任何一个成员服务器上运行。系统操作如同每个成员服务器上都有一个原始表的复本一样,但其实每个服务器上只有一个成员表和一个分布式分区视图。数据的位置对应用程序是透明的。 重建索引DBCC REINDEX ,DBCC INDEXDEFRAG,收缩数据和日志DBCC SHRINKDB,DBCC SHRINKFILE. 设置自动收缩日志.对于大的数据库不要设置数据库自动增长,它会降低服务器的性能。 在T-sql的写法上有很大的讲究,下面列出常见的要点:首先,DBMS处理查询计划的过程是这样的: 查询语句的词法、语法检查 将语句提交给DBMS的查询优化器 优化器做代数优化和存取路径的优化 由预编译模块生成查询规划 然后在合适的时间提交给系统处理执行 最后将执行结果返回给用户其次,看一下SQL SERVER的数据存放的结构:一个页面的大小为8K(8060)字节,8个页面为一个盘区,按照B树存放。 Commit和rollback的区别Rollback:回滚所有的事务。Commit:提交当前的事务.没有必要在动态SQL里写事务,如果要写请写在外面。如: begin tran exec(@s) commit […]
View Details监控SQL Server的运行状况
Microsoft SQL Server 2005 提供了一些工具来监控数据库。方法之一是动态管理视图。动态管理视图 (DMV) 和动态管理函数 (DMF) 返回的服务器状态信息可用于监控服务器实例的运行状况、诊断问题和优化性能。 常规服务器动态管理对象包括: dm_db_*:数据库和数据库对象 dm_exec_*:执行用户代码和关联的连接 dm_os_*:内存、锁定和时间安排 dm_tran_*:事务和隔离 dm_io_*:网络和磁盘的输入/输出 此部分介绍为监控 SQL Server 运行状况而针对这些动态管理视图和函数运行的一些常用查询。 示例查询 您可以运行以下查询来获取所有 DMV 和 DMF 名称:
1 |
<ol class="dp-sql"><li class="alt"><span><span class="keyword">SELECT</span><span> * </span><span class="keyword">FROM</span><span> sys.system_objects </span></span></li><li><span><span class="keyword">WHERE</span><span> </span><span class="keyword">name</span><span> </span><span class="op">LIKE</span><span> </span><span class="string">'dm_%'</span><span> </span></span></li><li class="alt"><span><span class="keyword">ORDER</span><span> </span><span class="keyword">BY</span><span> </span><span class="keyword">name</span><span> </span></span></li></ol> |
监控 CPU 瓶颈 CPU 瓶颈通常由以下原因引起:查询计划并非最优、配置不当、设计因素不良或硬件资源不足。下面的常用查询可帮助您确定导致 CPU 瓶颈的原因。 下面的查询使您能够深入了解当前缓存的哪些批处理或过程占用了大部分 CPU 资源。
1 |
<ol class="dp-sql"><li class="alt"><span><span class="keyword">SELECT</span><span> </span><span class="keyword">TOP</span><span> 50 </span></span></li><li><span> <span class="func">SUM</span><span>(qs.total_worker_time) </span><span class="keyword">AS</span><span> total_cpu_time, </span></span></li><li class="alt"><span> <span class="func">SUM</span><span>(qs.execution_count) </span><span class="keyword">AS</span><span> total_execution_count, </span></span></li><li><span> <span class="func">COUNT</span><span>(*) </span><span class="keyword">AS</span><span> number_of_statements, </span></span></li><li class="alt"><span> qs.sql_handle </span></li><li><span><span class="keyword">FROM</span><span> sys.dm_exec_query_stats </span><span class="keyword">AS</span><span> qs </span></span></li><li class="alt"><span><span class="keyword">GROUP</span><span> </span><span class="keyword">BY</span><span> qs.sql_handle </span></span></li><li><span><span class="keyword">ORDER</span><span> </span><span class="keyword">BY</span><span> </span><span class="func">SUM</span><span>(qs.total_worker_time) </span><span class="keyword">DESC</span><span> </span></span></li></ol> |
下面的查询显示缓存计划所占用的 CPU 总使用率(带 SQL 文本)。
1 |
<ol class="dp-sql"><li class="alt"><span><span class="keyword">SELECT</span><span> </span></span></li><li><span> total_cpu_time, </span></li><li class="alt"><span> total_execution_count, </span></li><li><span> number_of_statements, </span></li><li class="alt"><span> s2.text </span></li><li><span> <span class="comment">--(SELECT SUBSTRING(s2.text, statement_start_offset / 2, ((CASE WHEN statement_end_offset = -1 THEN (LEN(CONVERT(NVARCHAR(MAX), s2.text)) * 2) ELSE statement_end_offset END) - statement_start_offset) / 2) ) AS query_text</span><span> </span></span></li><li class="alt"><span><span class="keyword">FROM</span><span> </span></span></li><li><span> (<span class="keyword">SELECT</span><span> </span><span class="keyword">TOP</span><span> 50 </span></span></li><li class="alt"><span> <span class="func">SUM</span><span>(qs.total_worker_time) </span><span class="keyword">AS</span><span> total_cpu_time, </span></span></li><li><span> <span class="func">SUM</span><span>(qs.execution_count) </span><span class="keyword">AS</span><span> total_execution_count, </span></span></li><li class="alt"><span> <span class="func">COUNT</span><span>(*) </span><span class="keyword">AS</span><span> number_of_statements, </span></span></li><li><span> qs.sql_handle <span class="comment">--,</span><span> </span></span></li><li class="alt"><span> <span class="comment">--MIN(statement_start_offset) AS statement_start_offset, </span><span> </span></span></li><li><span> <span class="comment">--MAX(statement_end_offset) AS statement_end_offset</span><span> </span></span></li><li class="alt"><span> <span class="keyword">FROM</span><span> </span></span></li><li><span> sys.dm_exec_query_stats <span class="keyword">AS</span><span> qs </span></span></li><li class="alt"><span> <span class="keyword">GROUP</span><span> </span><span class="keyword">BY</span><span> qs.sql_handle </span></span></li><li><span> <span class="keyword">ORDER</span><span> </span><span class="keyword">BY</span><span> </span><span class="func">SUM</span><span>(qs.total_worker_time) </span><span class="keyword">DESC</span><span>) </span><span class="keyword">AS</span><span> stats </span></span></li><li class="alt"><span> <span class="op">CROSS</span><span> APPLY sys.dm_exec_sql_text(stats.sql_handle) </span><span class="keyword">AS</span><span> s2 </span></span></li></ol> |
下面的查询显示 CPU 平均占用率最高的前 50 个 SQL 语句。
1 |
<ol class="dp-sql"><li class="alt"><span><span class="keyword">SELECT</span><span> </span><span class="keyword">TOP</span><span> 50 </span></span></li><li><span>total_worker_time/execution_count <span class="keyword">AS</span><span> [</span><span class="func">Avg</span><span> CPU </span><span class="keyword">Time</span><span>], </span></span></li><li class="alt"><span>(<span class="keyword">SELECT</span><span> </span><span class="func">SUBSTRING</span><span>(text,statement_start_offset/2,(</span><span class="func">CASE</span><span> </span><span class="keyword">WHEN</span><span> statement_end_offset = -1 </span><span class="keyword">then</span><span> LEN(</span><span class="func">CONVERT</span><span>(nvarchar(</span><span class="keyword">max</span><span>), text)) * 2 </span><span class="keyword">ELSE</span><span> statement_end_offset </span><span class="keyword">end</span><span> -statement_start_offset)/2) </span><span class="keyword">FROM</span><span> sys.dm_exec_sql_text(sql_handle)) </span><span class="keyword">AS</span><span> query_text, * </span></span></li><li><span><span class="keyword">FROM</span><span> sys.dm_exec_query_stats </span></span></li><li class="alt"><span><span class="keyword">ORDER</span><span> </span><span class="keyword">BY</span><span> [</span><span class="func">Avg</span><span> CPU </span><span class="keyword">Time</span><span>] </span><span class="keyword">DESC</span><span> </span></span></li></ol> |
下面显示用于找出过多编译/重新编译的 DMV 查询。
1 |
<ol class="dp-sql"><li class="alt"><span><span class="keyword">select</span><span> * </span><span class="keyword">from</span><span> sys.dm_exec_query_optimizer_info </span></span></li><li><span><span class="keyword">where</span><span> </span></span></li><li class="alt"><span> counter = <span class="string">'optimizations'</span><span> </span></span></li><li><span> <span class="op">or</span><span> counter = </span><span class="string">'elapsed time'</span><span> </span></span></li></ol> |
下面的示例查询显示已重新编译的前 25 个存储过程。plan_generation_num 指示该查询已重新编译的次数。
1 |
<ol class="dp-sql"><li class="alt"><span><span class="keyword">select</span><span> </span><span class="keyword">top</span><span> 25 </span></span></li><li><span> sql_text.text, </span></li><li class="alt"><span> sql_handle, </span></li><li><span> plan_generation_num, </span></li><li class="alt"><span> execution_count, </span></li><li><span> dbid, </span></li><li class="alt"><span> objectid </span></li><li><span><span class="keyword">from</span><span> sys.dm_exec_query_stats a </span></span></li><li class="alt"><span> <span class="op">cross</span><span> apply sys.dm_exec_sql_text(sql_handle) </span><span class="keyword">as</span><span> sql_text </span></span></li><li><span><span class="keyword">where</span><span> plan_generation_num > 1 </span></span></li><li class="alt"><span><span class="keyword">order</span><span> </span><span class="keyword">by</span><span> plan_generation_num </span><span class="keyword">desc</span><span> </span></span></li></ol> |
效率较低的查询计划可能增大 CPU 占用率。 下面的查询显示哪个查询占用了最多的 CPU 累计使用率。
1 |
<ol class="dp-sql"><li class="alt"><span><span class="keyword">SELECT</span><span> </span></span></li><li><span> highest_cpu_queries.plan_handle, </span></li><li class="alt"><span> highest_cpu_queries.total_worker_time, </span></li><li><span> q.dbid, </span></li><li class="alt"><span> q.objectid, </span></li><li><span> q.number, </span></li><li class="alt"><span> q.encrypted, </span></li><li><span> q.[text] </span></li><li class="alt"><span><span class="keyword">from</span><span> </span></span></li><li><span> (<span class="keyword">select</span><span> </span><span class="keyword">top</span><span> 50 </span></span></li><li class="alt"><span> qs.plan_handle, </span></li><li><span> qs.total_worker_time </span></li><li class="alt"><span> <span class="keyword">from</span><span> </span></span></li><li><span> sys.dm_exec_query_stats qs </span></li><li class="alt"><span> <span class="keyword">order</span><span> </span><span class="keyword">by</span><span> qs.total_worker_time </span><span class="keyword">desc</span><span>) </span><span class="keyword">as</span><span> highest_cpu_queries </span></span></li><li><span> <span class="op">cross</span><span> apply sys.dm_exec_sql_text(plan_handle) </span><span class="keyword">as</span><span> q </span></span></li><li class="alt"><span><span class="keyword">order</span><span> </span><span class="keyword">by</span><span> highest_cpu_queries.total_worker_time </span><span class="keyword">desc</span><span> </span></span></li></ol> |
下面的查询显示一些可能占用大量 CPU 使用率的运算符(例如 ‘%Hash Match%’、‘%Sort%’)以找出可疑对象。
1 |
<ol class="dp-sql"><li class="alt"><span><span class="keyword">select</span><span> * </span></span></li><li><span><span class="keyword">from</span><span> </span></span></li><li class="alt"><span> sys.dm_exec_cached_plans </span></li><li><span> <span class="op">cross</span><span> apply sys.dm_exec_query_plan(plan_handle) </span></span></li><li class="alt"><span><span class="keyword">where</span><span> </span></span></li><li><span> <span class="func">cast</span><span>(query_plan </span><span class="keyword">as</span><span> nvarchar(</span><span class="keyword">max</span><span>)) </span><span class="op">like</span><span> </span><span class="string">'%Sort%'</span><span> </span></span></li><li class="alt"><span> <span class="op">or</span><span> </span><span class="func">cast</span><span>(query_plan </span><span class="keyword">as</span><span> nvarchar(</span><span class="keyword">max</span><span>)) </span><span class="op">like</span><span> </span><span class="string">'%Hash Match%'</span><span> </span></span></li></ol> |
[…]
View DetailsJavaScript 面向对象程序设计(下)——继承与多态
1 又是几个基本概念 为什么要说又呢? 在讨论继承时,我们已经列出了一些基本概念了,那些概念是跟封装密切相关的概念,今天我们要讨论的基本概念,主要是跟继承与多态相关的,但是它们跟封装也有一些联系。 1.1 定义和赋值 变量定义是指用 var a; 这种形式来声明变量。 函数定义是指用 function a(…) {…} 这种形式来声明函数。 var a = 1; 是两个过程。第一个过程是定义变量 a,第二个过程是给变量 a 赋值。 同样 var a = function(…) {}; 也是两个过程,第一个过程是定义变量 a 和一个匿名函数,第二个过程是把匿名函数赋值给变量 a。 变量定义和函数定义是在整个脚本执行之前完成的,而变量赋值是在执行阶段完成的。 变量定义的作用仅仅是给所声明的变量指明它的作用域,变量定义并不给变量初始值,任何没有定义的而直接使用的变量,或者定义但没有赋值的变量,他们的值都是 undefined。 函数定义除了声明函数所在的作用域外,同时还定义函数体结构。这个过程是递归的,也就是说,对函数体的定义包括了对函数体内的变量定义和函数定义。 通过下面这个例子我们可以更明确的理解这一点: Java代码 alert(a); alert(b); alert(c); var a = "a"; function a() {} function b() {} var b = "b"; var c = "c"; var c = function() {} […]
View DetailsJavaScript 面向对象程序设计(上)——封装
JavaScript 是一种非常灵活的面向对象程序设计语言,它与传统的强类型的面向对象程序设计语言(如 C++,Java,C# 等)有很大不同,所以要实现如 C++、java、C# 当中的一些特性就需要换一种思考方式来解决。今天主要讨论如何在 JavaScript 脚本中实现数据的封装(encapsulation)。 数据封装说的简单点就是把不希望调用者看见的内容隐藏起来。它是面向对象程序设计的三要素之首,其它两个是继承和多态,关于它们的内容在后面再讨论。 关于数据封装的实现,在 C++、Java、C# 等语言中是通过 public、private、static 等关键字实现的。在 JavaScript 则采用了另外一种截然不同的形式。在讨论如何具体实现某种方式的数据封装前,我们先说几个简单的,大家所熟知却又容易忽略的 JavaScript 的概念。 1 几个基本概念 1.1 变量定义 在 JavaScript 语言中,是通过 var 关键字来定义变量的。 但是如果我们直接给一个没有使用 var 定义的变量赋值,那么这个变量就会成为全局变量。 一般情况下,我们应该避免使用没有用 var 定义的变量,主要原因是它会影响程序的执行效率,因为存取全局变量速度比局部变量要慢得多。 但是这种用法可以保证我们的变量一定是全局变量。 另外,为了保证速度,我们在使用全局变量时,可以通过 var 定义一个局部变量,然后将全局变量赋予之,由此可以得到一个全局变量的局部引用。 1.2 变量类型 没有定义的变量,类型为 undefined。 变量的值可以是函数。 函数在 JavaScript 中可以充当类的角色。 1.3 变量作用域 变量作用域是指变量生存周期的有效范围。 单纯用 { } 创建的块不能创建作用域。 with 将它包含的对象作用域添加到当前作用域链中,但 with 不创建新的作用域。with 块结束后,会将对象作用域从当前作用域链中删除。 try-catch 中,catch 的错误对象只在 catch 块中有效,但 catch 块中定义的变量属于当前作用域。 其它如 if、for、for-in、while、do-while、switch 等控制语句创建的块不能创建作用域。 用 function 创建的函数,会创建一个新的作用域添加到当前作用域中。 2 封装 下面我们就来讨论具体的封装。首先说一下大家最熟悉的几种封装:私有实例成员、公有实例成员和公有静态成员。最后会讨论一下大家所不熟悉的私有静态成员和静态类的封装办法。因为下面要讨论的是面向对象编程,所有当函数作为类来定义和使用时,我们暂且将其成为类。 2.1 私有实例成员 私有实例成员在 JavaScript 中实际上可以用函数内的局部变量来实现,它相当于类的私有实例成员。例如: class1 = function() { // private […]
View DetailsJavaScript定义类或函数的几种方式小结
提起面向对象我们就能想到类,对象,封装,继承,多态。在《javaScript高级程序设计》(人民邮电出版社,曹力、张欣译。英文名字是:Professional JavaScript for Web Developers)这本书中描述的还算比较详细。我们看看JavaScript中定义类的各种方法。 1.工厂方式 javaScript中创建自己的类和对象,我们应该是必须掌握的,我们都知道javaScript中对象的属性可以在对象创建后动态定义,比如下面的代码: 复制代码代码如下: <script type="text/javascript"> //定义 var oCar = new Object(); oCar.color = "red"; oCar.doors = 4; oCar.showColor = function() { alert(this.color); } //调用 oCar.showColor(); </script> 我们很容易使用oCar对象,但是我们创就是想创建多个Car实例。我们可以使用一个函数来封装上面的代码来实现:<script type="text/javascript"> 复制代码代码如下: //定义 function createCar() { var oCar = new Object(); oCar.color = "red"; oCar.doors = 4; oCar.showColor = function() { alert(this.color); } return oCar; } //调用 var ocar1 = createCar(); var ocar2 = createCar(); ocar1.color = "black"; ocar1.showColor(); ocar2.showColor(); </script> 顺便说一下,javaScript对象默认成员属性都是public 的。这种方式我们称为工厂方式,我们创造了能创建并返回特定类型的对象的工厂。 这样做有点意思了,但是在面向对象中我们经常使用创建对象的方法是: Car car=new Car(); 使用new 关键字已经深入人心,因此我们使用上面的方法去定义总感觉别扭,并且每次调用时都去创建新的属性以及函数,功能上也不实际。下来我们看看构造函数的形式定义类。 2.构造函数 这种方式看起来有点象工厂函数。具体表现如下: 复制代码代码如下: <script type="text/javascript"> //定义 function Car(color, doors) { this.color = color; this.doors = doors; this.showColor = function() { alert(this.color); }; } //调用 var car1 = new Car("red", 4); var car2 = new Car("blue", 4); car1.showColor(); car2.showColor(); </script> 看起来效果很明显,有差别了吧。感觉有点意思了。在构造函数内部创造对象使用this 关键字,使用new 运算符创建对象感觉非常亲切。但是也有点问题:每次new 对象时都会创建所有的属性,包括函数的创建,也就是说多个对象完全独立,我们定义类的目的就是为了共享方法以及数据,但是car1对象与car2对象都是各自独立的属性与函数,最起码我们应该共享方法。这就是原形方式的优势所在。 3.原型方式 利用对象的prototype属性,可把它看出创建新对象所依赖的原型。方法如下: 复制代码代码如下: <script type="text/javascript"> //定义 function Car() { }; Car.prototype.color = "red"; Car.prototype.doors = 4; Car.prototype.drivers = new […]
View DetailsJavascript面向对象编程(三):非构造函数的继承
这个系列的第一部分介绍了"封装",第二部分介绍了使用构造函数实现"继承"。 今天是最后一个部分,介绍不使用构造函数实现"继承"。 一、什么是"非构造函数"的继承? 比如,现在有一个对象,叫做"中国人"。 var Chinese = {nation:’中国'}; 还有一个对象,叫做"医生"。 var Doctor ={career:’医生'} 请问怎样才能让"医生"去继承"中国人",也就是说,我怎样才能生成一个"中国医生"的对象? 这里要注意,这两个对象都是普通对象,不是构造函数,无法使用构造函数方法实现"继承"。 二、object()方法 json格式的发明人Douglas Crockford,提出了一个object()函数,可以做到这一点。 function object(o) { function F() {} F.prototype = o; return new F(); } 这个object()函数,其实只做一件事,就是把子对象的prototype属性,指向父对象,从而使得子对象与父对象连在一起。 使用的时候,第一步先在父对象的基础上,生成子对象: var Doctor = object(Chinese); 然后,再加上子对象本身的属性: Doctor.career = '医生'; 这时,子对象已经继承了父对象的属性了。 alert(Doctor.nation); //中国 三、浅拷贝 除了使用"prototype链"以外,还有另一种思路:把父对象的属性,全部拷贝给子对象,也能实现继承。 下面这个函数,就是在做拷贝: function extendCopy(p) { var c = {}; for (var i in p) { c[i] = p[i];} c.uber = p; return c;} 使用的时候,这样写: var Doctor = extendCopy(Chinese); Doctor.career = '医生'; alert(Doctor.nation); // 中国 但是,这样的拷贝有一个问题。那就是,如果父对象的属性等于数组或另一个对象,那么实际上,子对象获得的只是一个内存地址,而不是真正拷贝,因此存在父对象被篡改的可能。 请看,现在给Chinese添加一个"出生地"属性,它的值是一个数组。 Chinese.birthPlaces = ['北京',’上海',’香港']; 通过extendCopy()函数,Doctor继承了Chinese。 var Doctor = extendCopy(Chinese); 然后,我们为Doctor的"出生地"添加一个城市: […]
View DetailsJavascript面向对象编程(二):构造函数的继承
这个系列的第一部分,主要介绍了如何"封装"数据和方法,以及如何从原型对象生成实例。 今天要介绍的是,如何生成一个"继承"多个对象的实例。 比如,现在有一个"动物"对象的构造函数, function Animal(){ this.species = "动物"; } 还有一个"猫"对象的构造函数, function Cat(name,color){ this.name = name; this.color = color; } 怎样才能使"猫"继承"动物"呢? 1. 构造函数绑定 最简单的方法,大概就是使用call或apply方法,将父对象的构造函数绑定在子对象上,也就是在子对象构造函数中加一行: function Cat(name,color){ Animal.apply(this, arguments); this.name = name; this.color = color; } var cat1 = new Cat("大毛","黄色"); alert(cat1.species); // 动物 2. prototype模式 更常见的做法,则是使用prototype属性。 如果"猫"的prototype对象,指向一个Animal的实例,那么所有"猫"的实例,就能继承Animal了。 Cat.prototype = new Animal(); Cat.prototype.constructor = Cat; var cat1 = new Cat("大毛","黄色"); alert(cat1.species); // 动物 代码的第一行,我们将Cat的prototype对象指向一个Animal的实例。 Cat.prototype = new Animal(); 它相当于完全删除了prototype 对象原先的值,然后赋予一个新值。但是,第二行又是什么意思呢? Cat.prototype.constructor = Cat; 原来,任何一个prototype对象都有一个constructor属性,指向它的构造函数。也就是说,Cat.prototype 这个对象的constructor属性,是指向Cat的。 我们在前一步已经删除了这个prototype对象原来的值,所以新的prototype对象没有constructor属性,所以我们必须手动加上去,否则后面的"继承链"会出问题。这就是第二行的意思。 总之,这是很重要的一点,编程时务必要遵守。下文都遵循这一点,即如果替换了prototype对象, o.prototype = {}; 那么,下一步必然是为新的prototype对象加上constructor属性,并将这个属性指回原来的构造函数。 o.prototype.constructor = o; 3. 直接继承prototype 由于Animal对象中,不变的属性都可以直接写入Animal.prototype。所以,我们也可以让Cat()跳过 Animal(),直接继承Animal.prototype。 现在,我们先将Animal对象改写: function […]
View DetailsJavascript 面向对象编程(一):封装
学习Javascript,最难的地方是什么? 我觉得,Object(对象)最难。因为Javascript的Object模型很独特,和其他语言都不一样,初学者不容易掌握。 下面就是我的学习笔记,希望对大家学习这个部分有所帮助。我主要参考了以下两本书籍: 《面向对象的Javascript》(Object-Oriented JavaScript) 《Javascript高级程序设计(第二版)》(Professional JavaScript for Web Developers, 2nd Edition) 它们都是非常优秀的Javascript读物,推荐阅读。 笔记分成三部分。今天的第一部分是讨论"封装"(Encapsulation),后面的第二部分和第三部分讨论"继承"(Inheritance)。 ============================ Javascript 面向对象编程(一):封装 作者:阮一峰 Javascript是一种基于对象(object-based)的语言,你遇到的所有东西几乎都是对象。但是,它又不是一种真正的面向对象编程(OOP)语言,因为它的语法中没有class(类)。 那么,如果我们要把"属性"(property)和"方法"(method),封装成一个对象,甚至要从原型对象生成一个实例对象,我们应该怎么做呢? 1. 生成对象的原始模式 假定我们把猫看成一个对象,它有"名字"和"颜色"两个属性。 var Cat = { name : ", color : " } 现在,我们需要根据这个原型对象,生成两个实例对象。 var cat1 = {}; // 创建一个空对象 cat1.name = "大毛"; // 按照原型对象的属性赋值 cat1.color = "黄色"; var cat2 = {}; cat2.name = "二毛"; cat2.color = "黑色"; 好了,这就是最简单的封装了。但是,这样的写法有两个缺点,一是如果多生成几个实例,写起来就非常麻烦;二是实例与原型之间,没有任何办法,可以看出有什么联系。 2. 原始模式的改进 我们可以写一个函数,解决代码重复的问题。 function Cat(name,color){ return { name:name, color:color } } 然后生成实例对象,就等于是在调用函数: var cat1 = Cat("大毛","黄色"); var cat2 = Cat("二毛","黑色"); 这种方法的问题依然是,cat1和cat2之间没有内在的联系,不能反映出它们是同一个原型对象的实例。 3. 构造函数模式 为了解决从原型对象生成实例的问题,Javascript提供了一个构造函数(Constructor)模式。 所谓"构造函数",其实就是一个普通函数,但是内部使用了this变量。对构造函数使用new运算符,就能生成实例,并且this变量会绑定在实例对象上。 比如,猫的原型对象现在可以这样写, function Cat(name,color){ […]
View Details手机web-viewport
<meta name="viewport" content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=yes"/>
View DetailsSoybeanMilk-1.0-b4 Java MVC开发框架发布
SoybeanMilk-1.0-b4 做了较大的改进,包括: 增强泛型类型支持,框架现在支持自动将请求参数转换为调用方法的泛型类型参数 为<invoke>标签增加“breaker”属性,用以控制调用方法是否执行 一个新的转换异常类ParamConvertException被加入,用于追踪输入非法的请求参数 一个新的标签<type-target-handler>被加入,用于自定义动作目标处理器 BUG修复:默认通用转换器的getProperty接口不支持null输入 您可以点击 这里 下载框架包,里面包含了完整的说明文档和示例。 SoybeanMilk是一个极其简易、友好、且零侵入的Java MVC实现框架: 它几乎没有学习成本,你只需要熟悉jsp和servlet技术 也不需要你遵从任何代码编写模式 你的代码中找不到任何这个框架的踪迹
View Details