- 浏览: 1460380 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
luhouxiang:
写的很不错,学习了
Extjs 模块化动态加载js实践 -
kingkongtown:
如果想改成淘宝后台那样,可以在编辑器批量上传图片呢?
kissy editor 阶段体会 -
317966578:
兄弟我最近也在整jquery和caja 开放一些接口。在git ...
caja 原理 : 前端 -
liuweihug:
Javascript引擎单线程机制及setTimeout执行原 ...
setTimeout ,xhr,event 线程问题 -
辽主临轩:
怎么能让浏览器不进入 文档模式的quirks模式,进入标准的
浏览器模式与文本模式
概念:
在 lifesinger 处看到了关于兼容性的讨论,早先也有过类似的想法 ,其中提到了对象重写,恰好最近也频繁用到,这里对一个实例进行讲解下。所谓对象属性重写(特别是方法),即在运行时动态修改对象的属性以及方法,属于脚本语言所特有,如文中兼容层处理,在运行中对方法进行重写改变。
var obj = { run: function () { //action3 } }; if (condition) { obj.run = function { //action2 }; }
实例优化 step by step:
常见的浮动窗口实现。
1.最简单的类:
function Dialog() { this.el = new Node("<div style='display:none;position:absolute;left:100px;top:100px'>我是窗口</div>") document.body.appendChild(this.el[0]); } Dialog.prototype = { constructor: Dialog, show: function () { this.el.css("display", ""); }, hide: function () { this.el.css("display", "none"); } };
缺点:产成实例后即生成 div 节点,如果用户用不到(永远不弹出),则白白消耗了宝贵的 dom 操作,下面即照着这个思路进行优化
2.利用标志,on-demand 创建节点
function Dialog_v2() { } Dialog_v2.prototype = { constructor: Dialog_v2, show: function () { if (!this.init) { this.el = new Node("<div style='display:none;position:absolute;left:100px;top:100px'>我是窗口</div>") document.body.appendChild(this.el[0]); this.init = true; } this.el.css("display", ""); }, hide: function () { this.el.css("display", "none"); } };
静态语言的思路,增加标志 (this.init) 来控制初始化的次数,只有在第一次显示时才进行创建。(这里也可以判断 this.el 的存在与否,道理相同)
3.直观的对象方法重写
function Dialog_v3() { } Dialog_v3.prototype = { constructor: Dialog_v3, show: function () { this.el = new Node("<div style='display:none;position:absolute;left:100px;top:100px'>我是窗口</div>") document.body.appendChild(this.el[0]); var self = this; self.show = function () { self.el.css("display", ""); }; self.show(); }, hide: function () { this.el.css("display", "none"); } };
缺点:1.不够分离与自动化,每次都得在原函数中进行操作,和原有逻辑混在一起。
2.增加了内存占用,在实例自身中创建函数,取代了原型链查询,但也同时提升了访问速度。
3.若用户开始就注册 this.show 到 dom 节点事件,则后面重写无效。
4.分离自动化的的对象方法重写
步鄹详解:
1.分离初始化动作(_prepare) 与实际动作(_real),利用lazyRun公共机制串联。
2.lazyRun在实例生成后立即重写 _prepare。 调用 _prepare 时,先调用自身,再调用实际操作代码_real,最后用 _real 重写自己。
3.不修改对外接口 show,show 中直接调用 _prepare,可用它做为事件回调函数。
/* 核心机制,串联 obj[before] 与 obj[after],并在第一次执行后替换 obj[before] 为 obj[after] */ var lazyRun = function (obj, before, after) { var b = obj[before], a = obj[after]; obj[before] = function () { b.apply(this, arguments); a.apply(this, arguments); obj[before] = obj[after]; }; }; function Dialog_v4() { lazyRun(this, "_prepare", "_real"); } Dialog_v4.prototype = { constructor: Dialog_v4, show: function () { this._prepare(); }, _real: function () { this.el.css("display", ""); }, _prepare: function () { this.el = new Node("<div style='display:none;position:absolute;left:100px;top:100px'>我是窗口</div>"); document.body.appendChild(this.el[0]); }, hide: function () { this.el.css("display", "none"); } };
5.进阶的原型方法重写
在 4 中我们进行了实例方法的重写,实际是将方法从构造器原型移到了对象实例,而实例所属构造器的原型并没有发生变化,这一步尝试进行构造器原型方法的重写,达到影响该构造器所有实例的目的。
场景:
还是弹窗,但是常常伴随着遮罩层(mask),遮罩层是所有 dialog 实例公用,但是如果一开始就创建遮罩层,就显得有点浪费(实例还没生成呢),所有我们常常这样处理:
function Mask() {} function Dialog_v5() {} Dialog_v5.prototype = { prototype: Dialog_v5, show: function () { if (!Dialog_v5.mask) { Dialog_v5.mask = new Mask(); } //use mask } };
按照优化4 的思路,直接重写原型方法:
function Dialog_v6() { } Dialog_v6.prototype = { prototype: Dialog_v6, _prepare: function () { Dialog_v6.mask = new Mask(); }, _real: function () { //use mask }, show: function () { this._prepare(); } }; lazyRun(Dialog_v6.prototype, "_prepare", "_real");
这样的话当某个实例第一次执行 show 时会运行 _prepare 而初始化 mask,随之构造器的原型立即被更改,则以后所有的弹窗实例 show 时都会直接运行构造器原型上被覆盖后的 _prepare 即 _real,达到了 所有实例共享 mask 的目的。
总结:
提升效率有很多方面,对于web页面(特别是首页)开发来说就是加快初屏载入速度(减少startup latency ,提升 perceptive speed),一个有效方法就是尽可能得将资源延迟到它真正需要的时候才分配,例如宏观方面的 datalazyloader 。PS:和这篇文章 中的 “You can often cut the script-portion of your page load time the most by simply redesigning your code to do less work up front . defers execution whenever possible. ”有相似之处。
而在代码的微观粒度,如果为了达到这个目的而盲目得添加 if 绝不是明智之举,通过本文的方法重写,不但可以真正将初始化逻辑与使用逻辑分离,而且节省了条件判断,初始化后将自身重定向到真正的业务处理逻辑,天然的保证了初始化的单一性。
至于是要重写实例方法还是构造器原型方法,则要仔细分析资源的所有权,若资源是属于实例所有,如窗口的 dom 节点,则要重写实例方法,若资源属于类(构造器),需要在所有的实例间共享,如所有窗口的公共遮罩层,那么这种情形下更适合直接重写构造器原型。
修订于:2010-08-12
评论
应该被改变,因为所有实例共享mask遮罩层的
最后一个例子是重写构造器原型,
lazyRun不在原型方法中,在外边
当某个实例第一次运行show时,导致其构造器原型被重写,其它实例再show时就会跳过mask初始化了
function Dialog_v6() { } Dialog_v6.prototype = { prototype: Dialog_v6, _prepare: function () { Dialog_v6.mask = new Mask(); }, _real: function () { //use mask }, show: function () { this._prepare(); } }; lazyRun(Dialog_v6.prototype, "_prepare", "_real");
lazyRun怎么在第一次实例化时起作用?
function Dialog_v6() { } Dialog_v6.prototype = { prototype: Dialog_v6, _prepare: function () { Dialog_v6.mask = new Mask(); lazyRun(Dialog_v6.prototype, "_prepare", "_real"); }, _real: function () { //use mask }, show: function () { this._prepare(); } };
当然这个看怎么权衡了
这种方法感觉不利于扩展
例如在扩展或继承中想在show前加一段程序就出问题了
那hide是不是也加一个_prepare
这样会增加很多复杂度整个程序会变得很难维护
为什么要先调用hide,未创建或刚创建出来都是和hide状态一样的,如果要处理的话就是:
hide:function(){
this.el&&this.el.css("display","none");
}
那hide是不是也加一个_prepare
这样会增加很多复杂度整个程序会变得很难维护
发表评论
-
continuation, cps
2013-09-12 16:49 2791起 随着 nodejs 的兴起,异步编程成为一种潮流 ... -
一种基于匹配回朔的 css3 选择器引擎实现
2013-05-07 20:40 3401一种基于匹配回朔的 css3 选择器引擎实现 介绍 C ... -
cubic-bezier 模拟实现
2013-01-05 16:34 14089cubic-bezier 曲线是 css3 动画的一个重要基石 ... -
构建前端 DSL
2012-10-11 22:10 5359目前在传统的软件开 ... -
Get cursor position and coordinates from textarea
2012-04-10 20:50 5037最近需要从 textarea 中获 ... -
兼容 ie 的 transform
2012-02-23 14:00 6424css 2d transform 是 css3 引入的一个新的 ... -
promise api 与应用场景
2012-02-07 17:34 7375promise 是 commonjs 社区中提出的异步规范,其 ... -
closure compiler 代码优化实例
2012-01-08 03:23 2829closure compiler 可以进行不少有意思的优化 ... -
write html parser
2011-12-01 02:48 2916首先需要声明 html 不能用正则表达式来直接匹配进行内容抽取 ... -
获取剪贴板数据
2011-11-07 23:31 6447兼容性: 获取剪贴板数据这块各个浏览器间存在很大的 ... -
url 映射问题
2011-11-07 21:52 3221背景 url mapping 我最早知道是作为 j ... -
tip:如何原生播放声音
2011-10-19 12:45 2977如果不想考虑浏览器间 ... -
转载:瀑布流布局浅析
2011-09-29 19:02 2845简介 如果你经 ... -
cross domain request
2011-09-29 18:39 2846场景 跨域请求是随着 ... -
基于多继承的树设计
2011-09-18 03:42 2268分类 树是一种常见 ... -
caja 原理 : 前端
2011-09-01 16:48 7047作为前端开放的基础安全保证,caja 是目前比较合 ... -
tokenization of html
2011-08-29 22:38 2786html 符号解析问题 场景: 在页面上输出包 ... -
ie 下 cloneNode 导致的属性克隆
2011-08-24 16:10 2475这个还是很值得记下,一直存在的很大隐患终于解决,由于在 ie& ... -
循环引用下的深度克隆
2011-08-04 20:39 2306深度复制和浅度复制 是当初初学 c 遇到的第一批问题,似乎使 ... -
模块的静态与动态循环依赖
2011-07-25 03:43 3279场景: 循环依赖 我是不支持的,但现实中似乎又确实需 ...
相关推荐
在这个方法里,你可以使用Graphics对象绘制自己的控件样式,例如改变选中标签的颜色、形状、边框等。同时,可以利用DrawToBitmap方法生成预览图,用于实现平滑的动画效果。 2. **扩展事件处理**:原生TabControl的...
在面向对象编程中,子类可以重写父类的方法,以便实现不同的功能或优化已有行为。这被称为方法的重写。在PHP5中,当子类定义了一个与父类同名且签名相同的方法时,就实现了重写。例如,`animal.php`可能包含一个基本...
理解这些节点类型及其属性是使用解析表达式语法重写源代码的基础。 **三、解析与生成源代码** 1. **解析(Parse)**: 使用`ast.parse()`函数可以将Python源代码字符串转换为AST对象。 2. **遍历(Traversal)**: `...
标签"重写MenuStrip C#"强调了这是使用C#语言实现的,C#是.NET框架的主要开发语言之一,具有强大的面向对象特性和丰富的库支持。"好看的MenuStrip"暗示了这个控件在设计时注重了界面的美观性,可能包含了更现代的...
3. 自定义绘制:为了实现自定义的节点样式,可以重写`OnPaint`方法,使用`Graphics`对象进行绘制。这允许我们自由控制节点的颜色、形状、图标等。 4. 添加新功能:根据需求,可以添加新的属性、方法和事件。例如,...
3. **自定义单元格渲染**:为了实现更复杂的显示效果,如边框、图案填充等,我们需要重写`OnPaint`方法,使用`Graphics`对象进行绘制。这可能涉及到一些GDI+的知识,如画线、填充等。 ```csharp protected override...
总之,理解并正确重写 `equals()` 和 `hashCode()` 方法对于编写高质量的Java代码至关重要,这直接影响到对象比较的逻辑以及使用哈希表的数据结构的效率。通过遵循上述原则和最佳实践,我们可以确保对象的比较行为...
在WPF中,控件模板(ControlTemplate)用于定义控件的视觉结构,而数据模板(DataTemplate)则用于展示数据对象。 **一、创建自定义样式** 在WPF中,我们可以使用`<Style>`元素在XAML中定义样式。例如,要为`Window...
水印的位置、颜色、透明度等属性都可以根据需求进行调整。另一种方法是利用服务器控件,例如ASP.NET的Image服务器控件,通过CSS样式添加水印效果,这种方式更适用于动态生成的水印。 接下来,我们讨论URL重写。URL...
5. **构造器**:构造器用于初始化新创建的对象,学习者应了解构造器的语法和作用,以及如何使用构造器参数化对象的创建。 6. **方法重写(Override)与重载(Overload)**:学习者需要掌握如何根据需求重写父类的...
在Java的持久化框架中,Hibernate是一个非常流行的ORM(对象关系映射)工具,它使得开发者可以使用面向对象的方式来操作数据库。"重写hibernate的session简单增删改查"是一个针对初学者的实践教程,旨在帮助理解如何...
- 该类重写了`equals`方法,用于比较两个`Student`对象是否相同。这是实现列表比较的关键步骤之一。 3. **比较两个列表的不同项**: - 需要遍历第一个列表,对于每个元素,检查它是否存在于第二个列表中。 - ...
在这里,我们可以使用Canvas对象进行绘制,包括进度条的背景、进度指示器等。 2. **绘制逻辑**: - 使用`canvas.drawColor()`设置背景色,可以是纯色或渐变色。 - 使用`RectF`对象定义进度条的边界,然后使用`...
默认情况下,C#中的`Equals`方法和`GetHashCode`方法是通过引用来判断对象是否相等的,但当我们需要基于对象的属性来判断相等性时,就需要重写这两个方法。`GetHashCode`方法尤其关键,因为它在哈希表(如Dictionary...
- **重写(Override)**:使用`override`关键字重写父类的方法时,子类的方法会替代父类的方法,即当通过父类引用调用子类对象时,会执行子类中重写的方法。 - **覆盖(New)**:使用`new`关键字隐藏父类的方法时,子类...
### 对象存储元数据的索引与查询优化 #### 一、对象存储元数据的索引类型及选择策略 在对象存储系统中,元数据管理是核心组件之一,其主要功能包括存储对象的属性信息(如名称、创建时间、大小等)以及用于快速...
我们需要覆写`OnPaint`方法,使用`Graphics`对象来绘制背景图片,确保在控件大小变化时图片能够适配。在WPF中,我们则会使用XAML来定义样式和模板,包括设置`Background`属性为所需的图片。 2. **资源管理**:背景...
为了模仿QQ的外观,我们需要重写窗体的基本属性和方法,比如背景颜色、边框样式、控件布局等。 1. **重写窗体外观** - 使用`SetStyle`方法可以改变窗体的默认行为,例如禁用系统边框,以便我们可以自定义边框样式...
对象属性是每个对象独有的属性,即每个对象都可以拥有不同的属性值。对象属性用于表示每个对象特有的状态信息。当创建一个新的对象时,该对象将获得自己独立的一套属性值。 #### 三、面向过程编程与面向对象编程的...
- 性能优化:原生的CListCtrl在处理大量数据时可能会有性能问题,通过重写可以进行优化,比如使用虚拟列表模式(LVS_VIRTUAL)仅在需要时才绘制项。 - 错误修正:可能存在MFC库本身的bug,或者需要兼容特定环境下...