jQuery的$(document)对应原生JS写法及底层实现问询
好问题!咱们一步步把这个事儿拆解清楚:
$(document).attr('key', 'value')的原生JS实现 其实jQuery这里并没有给document设置真正的DOM属性,而是把数据存在了自己的内部缓存系统里。要实现同样的效果,有两种思路:
1. 贴合jQuery原行为的缓存实现
jQuery靠内置的$.data()系统来关联存储元素(包括document)的数据,咱们用原生的WeakMap就能模拟这个逻辑:
// 用WeakMap存数据,不会阻止document被垃圾回收,更合理 const docCache = new WeakMap(); // 设置属性 docCache.set(document, { key: 'value' }); // 获取属性 console.log(docCache.get(document).key); // 输出 'value'
2. 直接给document加自定义属性(如果要在调试器可见)
要是你希望这个属性能在控制台里直接看到,也可以直接给document对象加自定义属性:
document.key = 'value'; // 读取 console.log(document.key); // 输出 'value'
不过这个和jQuery的attr()行为不完全一致,因为jQuery并没有把数据存在DOM上,而是存在内存缓存里。
1. $(document)实际引用的是什么?
$(document)返回的是一个jQuery包装集合,这个集合里就包含了原生的document对象。你用$(document)[0]拿到的就是真实的document,所谓的“影子元素”只是Chrome调试器对jQuery包装对象的可视化展示而已,不是真实的DOM节点。
2. 为什么设置的属性在Chrome调试器里找不到?
因为jQuery的attr()方法对非Element类型的节点(比如document、window),根本不会调用原生的setAttribute,而是直接把数据塞进自己的内部缓存里。所以你在元素面板里看不到这个属性——它本来就没存在DOM上,只在jQuery的内存里。
3. 为什么document不能调用setAttribute?
因为setAttribute是Element接口的方法,而document属于Document接口,并不继承Element,自然没有这个方法。这也是jQuery不用setAttribute处理document的核心原因。
你可以在浏览器控制台里跑这段代码试试:
$(document).attr('key', 'testValue'); // 用jQuery的data方法能读到值 console.log($(document).data('key')); // 输出 'testValue' // 用原生方法读DOM属性,拿不到 console.log(document.getAttribute('key')); // 输出 null
这就能实锤jQuery是用缓存而非DOM属性来处理document的attr()调用啦。
内容的提问来源于stack exchange,提问作者CTS_AE

