【翻译】理念:无冲突的扩展本地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 ...
随机推荐
- 薪资至少10K的一道题,你能拿下吗
我所了解的华为: 应届本科生8k+ 应届硕士生10k+ 应届博士生12k+ 看到后什么感想?有没有只恨生不逢时运不佳的感觉? 很多人做3年多甚至更久,才能达到这个薪资水平,还不如一个新生. 在我看来, ...
- 从2-3-4树到红黑树(下) Java与C的实现
欢迎探讨,如有错误敬请指正 如需转载,请注明出处 http://www.cnblogs.com/nullzx/ 相关博客: 从2-3-4树到红黑树(上) 从2-3-4树到红黑树(中) 1. 实现技 ...
- List-style-type属性失效
异常处理汇总-前端系列:http://www.cnblogs.com/dunitian/p/4523015.html 看重点: 根本原因:padding: 0 0 0 0px; 解决:list-sty ...
- Sql Server系列:数据类型转换函数
T-SQL提供了两个显示转换的函数:CAST函数和CONVERT函数. 1. CAST函数 语法: CAST ( expression AS data_type [ ( length ) ] ) 示例 ...
- Caffe学习笔记1--Ubuntu 14.04 64bit caffe安装
本篇博客主要用于记录Ubuntu 14.04 64bit操作系统搭建caffe环境,目前针对的的是CPU版本: 1.安装依赖库 sudo apt-get install libprotobuf-dev ...
- .Net 转战 Android 4.4 日常笔记(2)--HelloWorld入门程序
我不知道人们为什么那么喜欢用HelloWorld来做为自己的第一个程序入门,为什么不是hello **其他的东西或者hi. 一.打开ADT 的Eclipse开发工具新建一个Android项目 New- ...
- android5.0联系人 sort_key改成phonebook_label
项目中用到了联系人根据字母排序,在android4.0手机上是可以的,但是在android4.4以上的手机排序是乱的,一般字母排序都是根据sort_key这个拼音进行排序,而android5.0这个字 ...
- IOS开发之自定义Button(集成三种回调模式)
前面在做东西的时候都用到了storyboard,在今天的代码中就纯手写代码自己用封装个Button.这个Button继承于UIView类,在封装的时候用上啦OC中的三种回调模式:目标动作回调,委托回调 ...
- 三行代码接入,社交软件打字时底下弹出的表情布局,自定义ViewPager+页面点标+各种功能的android小框架。
(转载请声明出处:http://www.cnblogs.com/linguanh/) 前言: 接上次分享的 ListView 动态加载类,入口:http://www.cnblogs.com/lingu ...
- swift2.0 如何隐藏和设置状态栏
1.在ViewController中操作当前ViewController的状态栏/** 隐藏状态栏 */ override func prefersStatusBarHidden() -> Bo ...