错误的选择器写法会严重影响性能,尤其是在复杂的DOM结构中。
// 1. 使用过于宽泛的选择器
$('div .content ul li a'); // 性能差
// 2. 重复使用选择器
$('#myList li').addClass('item');
$('#myList li').show();
$('#myList li').css('color', 'red');
// 3. 使用 :visible, :hidden 等伪类选择器
$('div:visible').hide(); // 性能差
// 4. 在循环中使用选择器
for (var i = 0; i < 1000; i++) {
$('.items').append('Item ' + i + '');
}
// 1. 使用更具体的选择器
$('#container .content li a'); // 性能更好
// 2. 缓存选择器结果
var $listItems = $('#myList li');
$listItems.addClass('item');
$listItems.show();
$listItems.css('color', 'red');
// 3. 避免使用性能差的伪类选择器
$('div').filter(':visible').hide(); // 稍好
// 或者使用CSS类
$('div.showing').hide();
// 4. 批量操作
var html = '';
for (var i = 0; i < 1000; i++) {
html += 'Item ' + i + '';
}
$('.items').append(html);
DOM操作是浏览器中最昂贵的操作之一,频繁操作会导致性能问题。
// 在循环中频繁操作DOM
var $list = $('#myList');
for (var i = 0; i < 100; i++) {
$list.append('Item ' + i + ' ');
}
// 频繁读写样式
$('#element').css('width', '100px');
$('#element').css('height', '100px');
$('#element').css('background', 'red');
$('#element').css('border', '1px solid black');
// 使用文档片段或字符串拼接
var $list = $('#myList');
var html = '';
for (var i = 0; i < 100; i++) {
html += 'Item ' + i + ' ';
}
$list.append(html);
// 批量设置样式
$('#element').css({
'width': '100px',
'height': '100px',
'background': 'red',
'border': '1px solid black'
});
// 或者使用CSS类
$('#element').addClass('styled-element');
// 陷阱:重复绑定事件
$('#button').click(function() {
// 每次点击都重新绑定
$('#other').click(handler);
});
function handler() {
console.log('被调用了多次!');
}
// 陷阱:未解绑事件
function initialize() {
$('#button').click(function() {
// 这个闭包引用了整个作用域
});
}
// 多次调用initialize会导致内存泄漏
initialize();
initialize();
// 1. 使用事件委托处理动态元素
// 不良做法
$('.dynamic-item').click(function() {
// 对新添加的元素无效
});
// 最佳实践:使用on()进行事件委托
$('#container').on('click', '.dynamic-item', function() {
// 对所有当前和未来的.dynamic-item都有效
});
// 2. 正确解绑事件
var $button = $('#button');
// 绑定事件时使用命名函数
function handleClick() {
console.log('clicked');
}
$button.on('click', handleClick);
// 需要时解绑
$button.off('click', handleClick);
// 3. 使用命名空间管理事件
$button.on('click.myNamespace', handleClick);
$button.off('click.myNamespace'); // 只解绑指定命名空间的事件
// 4. 一次性事件
$button.one('click', function() {
// 这个事件只会触发一次
console.log('只触发一次');
});
嵌套的AJAX调用和缺乏错误处理是常见问题。
// 深度嵌套的回调
$.get('/api/user', function(user) {
$.get('/api/posts/' + user.id, function(posts) {
$.get('/api/comments/' + posts[0].id, function(comments) {
$.get('/api/likes/' + comments[0].id, function(likes) {
// 四层嵌套,难以维护
console.log(likes);
});
});
});
});
// 1. 使用Promise/Deferred
$.when(
$.get('/api/user'),
$.get('/api/posts')
).then(function(userResponse, postsResponse) {
// 并行请求
var user = userResponse[0];
var posts = postsResponse[0];
return $.get('/api/comments/' + posts[0].id);
}).then(function(comments) {
// 链式调用
console.log(comments);
}).fail(function(error) {
// 统一错误处理
console.error('请求失败:', error);
});
// 2. 使用async/await(需要ES6+)
async function loadData() {
try {
const user = await $.get('/api/user');
const posts = await $.get('/api/posts/' + user.id);
const comments = await $.get('/api/comments/' + posts[0].id);
console.log(comments);
} catch (error) {
console.error('加载失败:', error);
}
}
// 意外创建全局变量
function leaky() {
leaked = "I'm global!"; // 没有var/let/const
}
// 闭包保持对外部变量的引用
function createLeak() {
var bigData = new Array(1000000);
return function() {
// 闭包引用了bigData
console.log(bigData.length);
};
}
// 移除元素但未解绑事件
var $element = $('#element').on('click', function() {
// 事件处理函数
});
// 仅仅移除元素,事件处理函数还在内存中
$element.remove();
// 未清理的定时器
var intervalId = setInterval(function() {
// 某些操作
}, 1000);
// 忘记清理
// clearInterval(intervalId);
// 1. 正确解绑事件
function setupComponent() {
var $component = $('#component');
function handleClick() { /* ... */ }
function handleMouseover() { /* ... */ }
$component.on('click', handleClick)
.on('mouseover', handleMouseover);
// 提供清理方法
return {
destroy: function() {
$component.off('click', handleClick)
.off('mouseover', handleMouseover)
.remove();
}
};
}
// 2. 管理数据缓存
$.data(element, 'key', largeObject);
// 清理时
$.removeData(element, 'key');
// 3. 使用WeakMap处理私有数据
const privateData = new WeakMap();
function Component(element) {
privateData.set(element, {
config: { /* 大量数据 */ }
});
// 元素被垃圾回收时,WeakMap中的引用自动清除
}
// 4. 避免循环引用
function createCircularReference() {
var obj1 = {};
var obj2 = {};
obj1.ref = obj2;
obj2.ref = obj1; // 循环引用!
// 解决方案:手动断开
// obj1.ref = null;
// obj2.ref = null;
}
// 使用IIFE创建私有作用域
(function($, window, document) {
'use strict'; // 严格模式
// 私有变量和函数
var privateVar = 'private';
function privateFunction() {
// 私有逻辑
}
// 公有接口
window.MyModule = {
init: function(options) {
// 初始化逻辑
return this;
},
destroy: function() {
// 清理逻辑
}
};
})(jQuery, window, document);
// 使用
MyModule.init({ /* 配置 */ });
// jQuery插件开发模式
(function($) {
'use strict';
// 默认配置
var defaults = {
speed: 400,
easing: 'swing'
};
// 插件构造函数
function Plugin(element, options) {
this.$element = $(element);
this.settings = $.extend({}, defaults, options);
this.init();
}
// 原型方法
Plugin.prototype = {
init: function() {
// 初始化逻辑
return this;
},
show: function() {
// 显示逻辑
return this;
},
hide: function() {
// 隐藏逻辑
return this;
},
destroy: function() {
// 清理
this.$element.off('.plugin');
$.removeData(this.$element[0], 'plugin');
}
};
// jQuery插件接口
$.fn.myPlugin = function(options) {
return this.each(function() {
if (!$.data(this, 'plugin')) {
$.data(this, 'plugin',
new Plugin(this, options));
}
});
};
})(jQuery);
// 良好的配置设计
var config = {
selectors: {
container: '#app',
button: '.btn-action',
content: '.content-area'
},
classes: {
active: 'is-active',
loading: 'is-loading',
hidden: 'is-hidden'
},
messages: {
loading: '加载中...',
error: '出错了!',
success: '操作成功!'
},
api: {
endpoints: {
users: '/api/users',
posts: '/api/posts'
},
timeout: 30000
}
};
// 使用配置
function initializeApp(config) {
var $container = $(config.selectors.container);
var $button = $(config.selectors.button);
$button.on('click', function() {
$container.addClass(config.classes.loading);
// 使用配置的API端点
$.get(config.api.endpoints.users)
.done(function() {
$container.removeClass(config.classes.loading)
.addClass(config.classes.success);
});
});
}
// 1. 检查jQuery对象
var $elements = $('.items');
console.log('找到元素数量:', $elements.length);
console.log('jQuery对象:', $elements);
console.log('DOM元素:', $elements.get());
// 2. 跟踪事件
$(document).on('click', function(e) {
console.log('点击事件:', e.target);
console.log('事件类型:', e.type);
console.log('页面坐标:', e.pageX, e.pageY);
});
// 3. 性能分析
console.time('操作耗时');
// 执行某些操作
for (var i = 0; i < 1000; i++) {
$('#test').append('' + i + '');
}
console.timeEnd('操作耗时');
// 4. 断言调试
function processData(data) {
console.assert(data, '数据不能为空');
console.assert(Array.isArray(data), '数据必须是数组');
// 处理逻辑
}
// 1. 检查事件绑定
// 在控制台输入
jQuery._data(document, 'events');
// 2. 链式调试
$('#element')
.addClass('test')
.data('debug', true)
.css({color: 'red'})
.queue(function(next) {
console.log('队列执行');
next();
});
// 3. 扩展jQuery进行调试
$.fn.debug = function() {
console.log('元素数量:', this.length);
console.log('选择器:', this.selector);
console.log('上下文:', this.context);
return this; // 保持链式调用
};
// 使用
$('.items').debug().hide();
// 4. 错误边界
try {
// 可能出错的代码
var result = $.parseJSON(invalidJson);
} catch (e) {
console.error('JSON解析错误:', e);
// 优雅降级
result = {};
}
// 检查jQuery是否可用
if (typeof jQuery === 'undefined') {
// 降级方案
console.warn('jQuery未加载,使用原生JS');
// 原生JavaScript实现
} else {
// 使用jQuery增强体验
$(function() {
// 增强功能
});
}
// 检查浏览器特性
if (typeof Promise !== 'undefined') {
// 使用Promise
$.get('/api/data').then(handleData);
} else {
// 使用回调
$.get('/api/data', handleData);
}
// 检查jQuery版本
if ($.fn.jquery >= '3.0.0') {
// 使用新特性
$.when.apply($, promises).then(...);
}
// 确保代码在无冲突模式下工作
(function($) {
'use strict';
// 在这里安全地使用$
$(function() {
// 初始化代码
});
})(jQuery.noConflict(true));
// 使用现代JavaScript特性
const config = {
apiUrl: '/api',
timeout: 5000
};
class MyComponent {
constructor(element) {
this.$element = $(element);
this.init();
}
init() {
// 使用箭头函数保持this
this.$element.on('click', () => {
this.handleClick();
});
}
handleClick() {
// 类方法
}
}
| 检查项 | 是否通过 | 说明 |
|---|---|---|
| 选择器是否高效? | 避免使用通用选择器,缓存重复使用的选择器 | |
| DOM操作是否批量处理? | 减少DOM操作次数,使用文档片段 | |
| 事件是否适当委托? | 对动态元素使用事件委托 | |
| 内存泄漏是否避免? | 解绑事件,清理数据缓存 | |
| 错误处理是否完善? | AJAX错误处理,try-catch关键代码 | |
| 代码是否模块化? | 使用IIFE、类、模块模式组织代码 | |
| 性能关键路径是否优化? | 分析并优化性能瓶颈 | |
| 是否支持无JavaScript? | 渐进增强,优雅降级 |
// 1. 防抖函数(防止频繁调用)
$.debounce = function(func, wait) {
var timeout;
return function() {
var context = this, args = arguments;
clearTimeout(timeout);
timeout = setTimeout(function() {
func.apply(context, args);
}, wait);
};
};
// 使用
$('#search').on('input', $.debounce(function() {
// 搜索逻辑,每300ms最多执行一次
performSearch($(this).val());
}, 300));
// 2. 节流函数(固定时间间隔执行)
$.throttle = function(func, limit) {
var inThrottle;
return function() {
var context = this, args = arguments;
if (!inThrottle) {
func.apply(context, args);
inThrottle = true;
setTimeout(function() {
inThrottle = false;
}, limit);
}
};
};
// 3. 安全获取数据属性
$.fn.getData = function(key) {
var data = this.data(key);
if (data === undefined) {
var attr = this.attr('data-' + key);
data = attr ? $.parseJSON(attr) : null;
}
return data;
};
// 4. 批量DOM操作优化
$.fn.appendMany = function(items) {
var fragment = document.createDocumentFragment();
$.each(items, function(i, item) {
fragment.appendChild($(item)[0]);
});
return this.append(fragment);
};