【翻译】理念:无冲突的扩展本地DOM原型
菜鸟翻译,望大家多多指正哈
原文:http://lea.verou.me/2015/04/idea-extending-native-dom-prototypes-without-collisions/
理念:无冲突的扩展本地DOM原型
正如我昨天在博文中指出,我不喜欢使用jQuery的原因之一是因为它的包装对象。对于jQuery来说,这是一个明智的决定:早在2006年它被第一次开发出来的时候,IE有一个非常讨厌的内存泄漏bug,当我们给一个元素添加属性时它便很容易被引发出来。哦,那时我们还没有在IE浏览器访问元素的原型,所以我们必须手动在每个元素上添加这些属性。Prototype.js试图走这条路但结果却是一团糟:他们打算改变他们之前在Prototype2.0版和依附包装对象的决定。有人曾写过很长的文章来批判企图扩展本地DOM元素是多么典型的错误想法。
第一个暴露元素原型的IE浏览器是IE8:我们可以访问Node.prototype,Element.prototype和其他几种原型。有些是多变的,有些则不是。在IE9,我们得到了全部,包括HTMLElement.prototype及其后代节点,比如HTMLParagraphElement。内存泄漏bug在IE8时得到了改善,到IE9时则得到了修复。但我们还是不要扩展原生的DOM元素,理由很充分:有冲突的风险。没有哪个函数库想在元素上添加一堆方法,这种方式很糟糕, 就像被邀请到别人家做客,结果却把人家家里弄的一团乱。
但是,如果我们可在避免冲突的条件下对元素添加方法呢?(好吧,从技术上讲,可能性很小)。我们只能对元素添加一个属性,然后把我们所有的方法都附着上去。例如:如果我们的函数库为yolo并有两个方法:foo()和bar(),就像这样:
var element = document.querySelector(".someclass");
element.yolo.foo();
element.yolo.bar();
//你甚至可以链式返回他们的元素
element.yolo.foo().yolo.bar();
可以肯定,这比包装对象更别扭,但是我认为使用本地DOM元素所带来的好处要大于它。当然,你可能不这么认为。
这基本上同我们做全局是完全一样的:我们都知道,添加大量的全局变量是不可取的做法,所以每一个函数库都只创建一个全局变量并把所有方法属性都附着在这个全局上。 然而,如果我们试图以这种天真的方式来实施,我们会发现 用我们的命名空间函数来引用元素是有些难度的:
Element.prototype.yolo = {
foo: function () {
console.log(this);
},
bar: function () { /* ... */ }};
someElement.yolo.foo(); // Object {foo: function, bar: function}
这里发生了什么?函数中的this指向的调用他们的对象,而不是对象所附着的那个元素,想要避开这个问题我们需要更聪明点。
记住:Yolo里的this 指向我们试图挂载方法的元素,但是我们没有运行任何代码,所以我们没有利用它。除非我们能够得到一个引用该对象的上下文。然而,运行一个function (例如element.yolo(). foo())会毁坏我们良好的API。
稍等一下,我们可以通过ES5获得权限!我们这样做:
Object.defineProperty(Element.prototype, "yolo", {
get: function () {
return {
element: this,
foo: function() {
console.log(this.element);
},
bar: function() { /* ... */ }
}
},
configurable: true,
writeable: false});
someElement.yolo.foo(); // It works! (打印出该元素)
这个方法奏效,但是这里有一个相当恼人的问题:我们每次生成该对象和重新定义函数都要调用该属性。这是一个很坏的想法。理想情况下,我们需要生成该对象,然后返回生成的对象。我们也不想让每个元素都有自己完全独立的实例,我们想在原型上定义这些函数,并且用JS完美的继承,因此,我们的库也是动态可扩展的。幸运的是,有一种方法可以做到这一切:
var Yolo = function(element) {
this.element = element;
};
Yolo.prototype = {
foo: function() {
console.log(this.element);
},
bar: function() { /* ... */ }
};
Object.defineProperty(Element.prototype, "yolo", {
get: function () {
Object.defineProperty(this, "yolo", {
value: new Yolo(this)
});
return this.yolo;
},
configurable: true,
writeable: false
});
someElement.yolo.foo(); // 成功! (打印出元素)
// 它也是可以动态扩展的
Yolo.prototype.baz = function(color) {
this.element.style.background = color;
};
someElement.yolo.baz("red") // 元素获得了一个红色背景
注意,上面我们所提到的getter只执行一次。之后它用一个静态值:一个yolo对象的实例重写了yolo属性。因为我们用 到Object.define Property()所以也不会遇到破坏枚举的问题(for..in循环),这些属性默认enumerable: false。这里任然有一个不足:这些方法需要用this.element来替代this。我们可以通过封装他们来解决这一问题:
for (let method in Yolo.prototype) {
Yolo.prototype[method] = function(){
var callback = Yolo.prototype[method];
Yolo.prototype[method] = function () {
var ret = callback.apply(this.element, arguments);
// 可链式返回元素!
return ret === undefined? this.element : ret;
}
}
}
然而,现在你不能动态的在Yolo.prototype上添加方法并让他们像element.yolo里的本地方法那样自动运行。所以它是有点痛的可扩展性(当然,你仍然可以用this.element来添加方法,也是可行的)。
你的想法?
【翻译】理念:无冲突的扩展本地DOM原型的更多相关文章
- 消息点击率翻倍的背后——闲鱼无侵入可扩展IFTTT系统
一.面临问题 在闲鱼生态里,用户之间会有很多种关系.其中大部分关系是由买家触发,联系到卖家,比如买家通过搜索.收藏.聊天等动作与卖家产生联系:另外一部分是平台与用户之间的关系.对这些关系分析之后我们发 ...
- DOM扩展:DOM API的进一步增强[总结篇-下]
本文承接<DOM扩展:DOM API的进一步增强[总结篇-上]>,继续总结DOM扩展相关的功能和API. 3.6 插入标记 DOM1级中的接口已经提供了向文档中插入内容的接口,但是在给文档 ...
- DOM扩展:DOM API的进一步增强[总结篇-上]
DOM1级主要定义了文档的底层结构,并提供了基本的查询操作的API,总体而言这些API已经比较完善,我们可以通过这些API完成大部分的DOM操作.然而,为了扩展DOM API的功能,同时进一步提高DO ...
- React系列文章:无状态组件生成真实DOM结点
在上一篇文章中,我们总结并模拟了JSX生成真实DOM结点的过程,今天接着来介绍一下无状态组件的生成过程. 先以下面一段简单的代码举例: const Greeting = function ({name ...
- React: 无状态组件生成真实DOM结点
在上一篇文章中,我们总结并模拟了 JSX 生成真实 DOM 结点的过程,今天接着来介绍一下无状态组件的生成过程. 先以下面一段简单的代码举例: const Greeting = function ({ ...
- [翻译]Review——The Inner Workings Of Virtual DOM
The Inner Workings Of Virtual DOM 虚拟DOM的内部工作机制 原文地址:https://medium.com/@rajaraodv/the-inner-workings ...
- js基础例子dom+原型+oop基础知识记录01
//oo:概念是计算机中对于现实世界的理解和抽象的方法 //由计算机利用编程技术发展到现在的产物 //面向对象几要素 //对象:由属性和方法组成的集合 //属性:保存数据,存储在对象内存空间中的唯一的 ...
- (翻译) Inheritance and the prototype chain 继承和原型链
JavaScript is a bit confusing for developers experienced in class-based languages (like Java or C++) ...
- Git的介绍及使用
一.配置用户信息: 配置用户名和邮箱: $ git config --global user.name "chunyu" $ git config --global user.em ...
随机推荐
- jQuery 2.0.3 源码分析core - 选择器
声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 打开jQuery源码,一眼看去到处都充斥着正则表达式,jQuery框架的基础就是查询了,查询文档元素对象 ...
- jQuery 2.0.3 源码分析 事件绑定 - bind/live/delegate/on
事件(Event)是JavaScript应用跳动的心脏,通过使用JavaScript ,你可以监听特定事件的发生,并规定让某些事件发生以对这些事件做出响应 事件的基础就不重复讲解了,本来是定位源码分析 ...
- Android初级教程_获取Android控件的宽和高
转载:http://blog.csdn.net/johnny901114/article/details/7839512 我们都知道在onCreate()里面获取控件的高度是0,这是为什么呢?我们来看 ...
- js学习内容的整理
1.jquery动态添加Table中的一行 function addTableRow(tableId){var html = '<tr>\ ......\ </tr>" ...
- BFC之宽度自适应布局篇
说到自适应布局,我们曾在“抛砖引玉之宽度自适应布局”一文中学习过.当时的核心思想主要是利用float+margin的形式.利用块状元素的流体特性,然后计算出float元素的宽度,并赋予到块状元素的相应 ...
- boa + ajax + cgi ajax请求cgi
最近公司要做一个通讯管理机,然后需要和另外一个同事一起做,我们需要用到boa+Ajax+CGI,以前没试过与CGI交互,一开始发现问题挺大的,用ajax请求cgi,总是不返回数据,又或者请求回来的是c ...
- 【记录】ASP.NET MVC MapRoute .htm 不起作用
RegisterRoutes 注册路由示例配置: public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRo ...
- canvas学习和面向对象(二)
Canvas 学习(二) 上一篇Canvas 学习(一)中我是用canvas绘制了一些基本和组合的图形. 现在开始绘制图片和动画帧,以及面向对象的升级版本. 还是一样,看代码,所有的代码都托管在git ...
- C# 在word中查找及替换文本
C# 在word中查找及替换文本 在处理word文档时,很多人都会用到查找和替换功能.尤其是在处理庞大的word文档的时候,Microsoft word的查找替换功能就变得尤为重要,它不仅能让我们轻易 ...
- Javascript进阶之路-论对象的重要性
要了解JavaScript对象,我们可以从对象创建.属性操作.对象方法这几个方面入手.概括起来,包括以下几模块: 1.创建对象 1.1 对象直接量 1.2 通过new创建对 ...