在浏览器中使用javascript __proto__作为实现算法的一部分
Using javascript __proto__ in browser, naturally, as part of implemented algorithms
考虑下面的代码片段,这里使用javascript原型继承来从DOM元素收集CSS属性。elem
数组包含DOM节点对应的对象,每个对象有一个style
字段,每个elem[x].style
也是一个对象。elem[x].style
对象重复DOM树层次结构,通过__proto__
连接。rootStyle
变量作为所有elem[x].style
原型链的根:
var rootStyle = {},
elem = [{}, {}, {}];
rootStyle.__proto__ = null;
rootStyle.fontSize = '14px';
elem[0].style = {};
elem[0].style.__proto__ = rootStyle;
elem[0].style.fontWeight = 'bold';
elem[0].className = 'my-elem-123';
elem[1].style = {};
elem[1].style.__proto__ = rootStyle;
elem[1].style.fontStyle = 'italic';
elem[1].className = 'my-elem-456';
elem[2].style = {};
elem[2].style.__proto__ = elem[1].style;
elem[2].style.textDecoration = 'underline';
elem[2].className = 'my-elem-789';
...
// later in the code
var cssCode = [],
i, len = 3;
for(i = 0; i < len; i++) {
cssCode.push('.' + elem[i].className + '{' + getCssRules(elem[i]) + '}';
}
function getCssRules(elem) {
var result = [],
cssProperty, cssValue;
for(cssProperty in elem.style) {
// No hasOwnProperty check!
// Here (and in for..in loop) happens the lookup magic that I need
cssValue = elem.style[cssProperty];
result.push(cssValue + ':' + cssProperty + ';';
}
return result;
}
正如这里所说:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto,我不应该因为性能影响而改变对象的原型。
对象键值查找在内部变成了许多操作,但这是可以接受的,它是一种托管语言,这里的任何操作都有开销。如果你不制作深度疯狂的原型链,那么原型链查找的速度应该与任何"单步"操作的速度相当,我的意思是,接近0(1)的复杂度。如果我的算法自然需要这样的数据结构和这样的行为,这是痛苦的屁股-实现我自己的链查找,或者一些完全不同的解决方案,只是因为"设置__proto__
是坏的"。
那么,__proto__
有哪些好的/坏的用法呢?
如果我像这样在elem
数组中存储对真实DOM节点的引用会发生什么:
elem[0].domNode = document.body.childNodes[0];
elem[1].domNode = document.body.childNodes[1];
elem[2].domNode = elem[1].domNode.childNodes[0];
用自定义原型链连接对象,用通用原型链连接对象,是好是坏,还是无所谓,引擎的优化在这里失败了吗?
添加:好了,现在我都明白了!设置__proto__
的所有令人困惑的东西都是关于更改__proto__
引用的。它会引发不好的事情(见第一条评论中的链接)。我们真的应该坚持使用公认答案中的语法。首先,我认为,糟糕的事情发生是因为空原型本身,缺乏一些成员,需要javascript引擎进行优化。
不考虑设置那么,
__proto__
的好/坏用法是什么呢?
__proto__
是否有好的用例,1您不需要在代码中这样做。而不是:创建没有原型的根目录:
rootStyle = Object.create(null);
使用rootStyle
作为原型创建对象:
elem[0].style = Object.create(rootStyle);
将其应用到代码的开头,而不做任何其他更改:
var rootStyle = Object.create(null), // **
elem = [{}, {}, {}];
rootStyle.fontSize = '14px';
elem[0].style = Object.create(rootStyle); // **
elem[0].style.fontWeight = 'bold';
elem[0].className = 'my-elem-123';
elem[1].style = Object.create(rootStyle); // **
elem[1].style.fontStyle = 'italic';
elem[1].className = 'my-elem-456';
elem[2].style = Object.create(elem[1].style); // **
elem[2].style.textDecoration = 'underline';
elem[2].className = 'my-elem-789';
如果我像这样在元素数组中存储对真实DOM节点的引用会发生什么:
elem[0].domNode = document.body.childNodes[0]; elem[1].domNode = document.body.childNodes[1]; elem[2].domNode = elem[1].domNode.childNodes[0];
elem
实例上的原型链的性质与如果您执行上述操作会发生什么问题完全无关。
如果你这样做了,"会发生什么"的答案是:没什么不寻常的(除非你处理的是一个过时的IE版本)。这是对元素的另一个引用,所以如果你在这样做之后删除(比如说)document.body
的第一个子元素,而不是被清理,它会一直存在,直到你在elem[0].domNode
中清除对它的引用,但这与你维护对任何其他对象的引用没有什么不同(再次,如果我们不谈论过时的IE版本)。
1三个音符:
如果您认为需要更改现有对象的原型,请退一步查看您的整体设计。这样做是非常不寻常的;从设计的角度来看,您最好创建一个正确类型的新对象,并复制任何相关信息。(在十多年的JavaScript编程生涯中,我从来没有这样做过。如果你用经典的OOP术语[c++, Java]来描述它,它就像在创建对象之后改变对象的类型一样;例如,您创建了一个
Cat
,但现在您想将其更改为Dog
。只是很少有真正需要这样做。正如您在MDN上看到的,更改对象的原型并不是JavaScript引擎优化的对象,因此作为一个例外情况,它往往会破坏对象的优化,减慢属性访问。当然,这种放缓是否以某种方式显着将因用例而异;
在现代JavaScript引擎上,如果你确实有一个真正的用例来改变原型,通过
Object.setPrototypeOf
而不是分配给__proto__
。
- 如何使用动画实现纸张推车
- 客户端服务器REST API captcha实现
- Luhn算法的实现
- 用Javascript实现算法
- 需要使用JavaScript实现我的算法
- 用Javascript实现了带有合并排序算法的反转计数
- 在 JavaScript 中实现 Dijkstra 算法的错误
- javascript中的星形算法实现
- 实现 A-Star 算法.请帮忙
- 使用 JavaScript 实现算法
- 在javascript中实现的网格简化算法
- 理解和实现基于力的图形布局算法
- 谷歌's SNAPPY算法在javascript中的实现(客户端)
- Javascript快速排序算法实现
- 在JS中寻找Blake-512哈希算法的实现
- 为什么Javascript实现的冒泡排序比其他排序算法快得多
- SVG / Raphael,如何在javascript中实现DOT算法?(图组织)
- 在浏览器中使用javascript __proto__作为实现算法的一部分
- 用java脚本实现Flood-Fill算法
- Node.js的目的是什么?[例如:在服务器上可用的数据集上实现图形算法]