菜鸟翻译,望大家多多指正哈

原文: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原型的更多相关文章

  1. 消息点击率翻倍的背后——闲鱼无侵入可扩展IFTTT系统

    一.面临问题 在闲鱼生态里,用户之间会有很多种关系.其中大部分关系是由买家触发,联系到卖家,比如买家通过搜索.收藏.聊天等动作与卖家产生联系:另外一部分是平台与用户之间的关系.对这些关系分析之后我们发 ...

  2. DOM扩展:DOM API的进一步增强[总结篇-下]

    本文承接<DOM扩展:DOM API的进一步增强[总结篇-上]>,继续总结DOM扩展相关的功能和API. 3.6 插入标记 DOM1级中的接口已经提供了向文档中插入内容的接口,但是在给文档 ...

  3. DOM扩展:DOM API的进一步增强[总结篇-上]

    DOM1级主要定义了文档的底层结构,并提供了基本的查询操作的API,总体而言这些API已经比较完善,我们可以通过这些API完成大部分的DOM操作.然而,为了扩展DOM API的功能,同时进一步提高DO ...

  4. React系列文章:无状态组件生成真实DOM结点

    在上一篇文章中,我们总结并模拟了JSX生成真实DOM结点的过程,今天接着来介绍一下无状态组件的生成过程. 先以下面一段简单的代码举例: const Greeting = function ({name ...

  5. React: 无状态组件生成真实DOM结点

    在上一篇文章中,我们总结并模拟了 JSX 生成真实 DOM 结点的过程,今天接着来介绍一下无状态组件的生成过程. 先以下面一段简单的代码举例: const Greeting = function ({ ...

  6. [翻译]Review——The Inner Workings Of Virtual DOM

    The Inner Workings Of Virtual DOM 虚拟DOM的内部工作机制 原文地址:https://medium.com/@rajaraodv/the-inner-workings ...

  7. js基础例子dom+原型+oop基础知识记录01

    //oo:概念是计算机中对于现实世界的理解和抽象的方法 //由计算机利用编程技术发展到现在的产物 //面向对象几要素 //对象:由属性和方法组成的集合 //属性:保存数据,存储在对象内存空间中的唯一的 ...

  8. (翻译) Inheritance and the prototype chain 继承和原型链

    JavaScript is a bit confusing for developers experienced in class-based languages (like Java or C++) ...

  9. Git的介绍及使用

    一.配置用户信息: 配置用户名和邮箱: $ git config --global user.name "chunyu" $ git config --global user.em ...

随机推荐

  1. JAVAScript控制多个下拉框

    方法:获取多选下拉框对象数组→循环判断option选项的selected属性(true为选中,false为未选中)→使用value属性取出选中项的值.实例演示如下: 这个东西我是在百度上查的,我为了方 ...

  2. GUID简介

    GUID (全局唯一标识符) 编辑 全局唯一标识符(GUID,Globally Unique Identifier)是一种由算法生成的二进制长度为128位的数字标识符.GUID主要用于在拥有多个节点. ...

  3. Utility2:Appropriate Evaluation Policy

    UCP收集所有Managed Instance的数据的机制,是通过启用各个Managed Instances上的Collection Set:Utility information(位于Managem ...

  4. Sql Server系列:数据表操作

    表是用来存储数据和操作数据的逻辑结构,用来组织和存储数据,关系数据库中的所有数据都表现为表的形式,数据表由行和列组成.SQL Server中的数据表分为临时表和永久表,临时表存储在tempdb系统数据 ...

  5. 关于Android多项目依赖在Eclipse中无法关联源代码的问题解决

    被Eclipse中Android依赖项目无法关联源代码的问题困扰了许久,网上搜索了一下,终于得到解决,大大提高了开发效率. 问题描述: 项目有A,B两个Android Project组成, B是And ...

  6. 坑爹的Maven

    之前没用过Maven,最近在研究Curator的时候,导入别人的工程,但是没有相应的包,需使用Maven解决依赖.于是各种折腾,最后虽然解决了,但中间的坑还不少.尽管网上也有相应的安装教程,但很多都是 ...

  7. 12个不可不知的Sublime Text应用技巧和诀窍

    本文为您提供Sublime Text编辑器的12个技巧和诀窍,深入挖掘这个看似简洁的代码编辑器,背后所隐藏的实现各种高级功能的无限可能. 1) 选择 以下是一些Sublime Text选择文本的快捷键 ...

  8. 【Java心得总结六】Java容器中——Collection

    在[Java心得总结五]Java容器上——容器初探这篇博文中,我对Java容器类库从一个整体的偏向于宏观的角度初步认识了Java容器类库.而在这篇博文中,我想着重对容器类库中的Collection容器 ...

  9. 8.Struts2类型转换器

    类型转换器1.引入在Struts2中,请求参数类型不仅可以是String,还可以是其它类型.如,定义一个请求参数birthday为Date类型,给其赋值为1949-10-1,则birthday接收到的 ...

  10. js作用域和变量提升

    Function declarations and variable declarations are always moved (“hoisted”) invisibly to the top of ...