主页/jQuery教程/与现代前端开发/从jQuery到现代原生JavaScript的替代方案

从jQuery到现代原生JavaScript的替代方案

9,816字
42–62 分钟

概览

目录

随着浏览器标准的统一和原生 JavaScript API的日益强大,许多曾经依赖 jQuery 的功能现在可以直接用原生代码实现。这并不意味着 jQuery 不再有价值,而是在现代项目中选择合适的技术时,了解原生替代方案有助于精简代码、减少依赖并提升性能。本章旨在提供一个 从jQuery到现代原生JavaScript的替代方案 的参考,涵盖最常见的操作场景,通过对比帮助开发者做出更明智的技术决策。

选择器与DOM查询

jQuery 最深入人心的功能之一是其强大的选择器引擎 $()。在现代浏览器中,document.querySelector()document.querySelectorAll() 提供了几乎同等的能力。

语法

// jQuery
var $elements = $('.my-class');

// 原生 JavaScript
var elements = document.querySelectorAll('.my-class');

querySelectorAll 返回一个静态的 NodeList,而非 jQuery 集合对象,因此不包含链式调用的方法。但它支持所有标准CSS选择器,足以应对绝大多数查询需求。

示例:选择器对比
以下示例展示了使用 jQuery 和原生方法进行相同DOM查询的操作。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>原生JavaScript替代方案示例:选择器</title>
</head>
<body>
    <div class="container">
        <ul id="list">
            <li class="item">项目1</li>
            <li class="item">项目2</li>
            <li class="item special">项目3(特殊)</li>
        </ul>
    </div>

    <script>
        // 原生 JavaScript 实现
        // 1. 通过 ID 获取元素
        const list = document.getElementById('list');
        console.log('原生 - ID:', list);

        // 2. 通过类名获取所有元素
        const items = document.querySelectorAll('.item');
        console.log('原生 - 类名 (.item) 数量:', items.length);

        // 3. 获取复合选择器
        const specialItem = document.querySelector('.item.special');
        console.log('原生 - 复合选择器 (.item.special):', specialItem.textContent);

        // 4. 遍历 NodeList
        items.forEach(item => {
            console.log('原生 - 遍历项目:', item.textContent);
        });

        /* jQuery 对比写法 (假设已加载 jQuery) 
        $(document).ready(function() {
            console.log('jQuery - ID:', $('#list').get(0));
            console.log('jQuery - 类名数量:', $('.item').length);
            console.log('jQuery - 复合选择器:', $('.item.special').text());
            $('.item').each(function() {
                console.log('jQuery - 遍历项目:', $(this).text());
            });
        });
        */
    </script>
</body>
</html>

DOM操作

jQuery 简化了DOM元素的创建、插入、修改和移除。原生 JavaScript 同样提供了完整的方法。

创建与插入元素

语法

// jQuery
var $newDiv = $('<div>').text('Hello').addClass('my-div');
$('body').append($newDiv);

// 原生 JavaScript
var newDiv = document.createElement('div');
newDiv.textContent = 'Hello';
newDiv.classList.add('my-div');
document.body.appendChild(newDiv);

修改内容与属性

语法

// jQuery
$('#my-link').attr('href', 'https://example.com').text('示例链接');

// 原生 JavaScript
var link = document.getElementById('my-link');
link.setAttribute('href', 'https://example.com');
link.textContent = '示例链接';

移除元素

语法

// jQuery
$('#my-element').remove();

// 原生 JavaScript
var element = document.getElementById('my-element');
element.remove(); // 现代浏览器
// 或 element.parentNode.removeChild(element); // 兼容旧版

示例:DOM操作对比
以下示例对比了使用 jQuery 和原生方法进行一系列DOM操作的代码。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>原生JavaScript替代方案示例:DOM操作</title>
</head>
<body>
    <div id="app">
        <p class="old">旧段落</p>
    </div>
    <button id="run-native">运行原生操作</button>
    <!-- <button id="run-jquery">运行jQuery操作 (需加载jQuery)</button> -->

    <script>
        document.getElementById('run-native').addEventListener('click', function() {
            const app = document.getElementById('app');

            // 1. 创建新元素
            const newParagraph = document.createElement('p');
            newParagraph.textContent = '这是一个新段落';
            newParagraph.classList.add('new');

            // 2. 插入元素
            app.appendChild(newParagraph);

            // 3. 修改现有元素
            const oldParagraph = document.querySelector('.old');
            if (oldParagraph) {
                oldParagraph.innerHTML = '旧段落已被<strong>修改</strong>';
                oldParagraph.style.color = 'blue';
            }

            // 4. 删除元素 (删除刚添加的新段落)
            // newParagraph.remove(); // 现代方式
            if (newParagraph.parentNode) {
                newParagraph.parentNode.removeChild(newParagraph); // 兼容方式
            }

            // 5. 操作属性
            const button = document.getElementById('run-native');
            button.setAttribute('data-status', 'clicked');
            button.disabled = true; // 直接操作属性
        });

        /* jQuery 版本对比
        $('#run-jquery').on('click', function() {
            var $app = $('#app');

            // 1. 创建新元素并插入
            $('<p>', {
                text: '这是一个新段落',
                class: 'new'
            }).appendTo($app);

            // 2. 修改现有元素
            $('.old').html('旧段落已被<strong>修改</strong>').css('color', 'blue');

            // 3. 删除新添加的元素
            $app.find('.new').remove();

            // 4. 操作属性
            $('#run-jquery').attr('data-status', 'clicked').prop('disabled', true);
        });
        */
    </script>
</body>
</html>

事件处理

jQuery.on() 方法提供了统一的事件绑定接口。原生 JavaScript 使用 addEventListener 同样强大且灵活。

语法

// jQuery
$('#my-button').on('click', function(e) {
    console.log('按钮被点击', e.target);
});

// 原生 JavaScript
document.getElementById('my-button').addEventListener('click', function(e) {
    console.log('按钮被点击', e.target);
});

事件委托

jQuery 的事件委托十分简洁。原生实现同样利用事件冒泡。

语法

// jQuery - 事件委托
$('#parent-list').on('click', 'li', function() {
    console.log('列表项被点击');
});

// 原生 JavaScript - 事件委托
document.getElementById('parent-list').addEventListener('click', function(e) {
    if (e.target && e.target.matches('li')) {
        console.log('列表项被点击');
    }
});

示例:事件处理对比
以下示例展示了事件绑定和事件委托在两种技术中的实现。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>原生JavaScript替代方案示例:事件处理</title>
</head>
<body>
    <ul id="todo-list">
        <li>学习原生API</li>
        <li>理解事件委托</li>
    </ul>
    <button id="add-item">添加待办</button>

    <script>
        const list = document.getElementById('todo-list');
        const addBtn = document.getElementById('add-item');

        // 原生事件委托:监听父元素上的点击事件
        list.addEventListener('click', function(e) {
            if (e.target && e.target.tagName === 'LI') {
                e.target.style.textDecoration = 'line-through';
                console.log('完成事项:', e.target.textContent);
            }
        });

        // 原生事件绑定:添加新项
        addBtn.addEventListener('click', function() {
            const newItem = document.createElement('li');
            newItem.textContent = '新事项 ' + (list.children.length + 1);
            list.appendChild(newItem);
        });

        /* jQuery 版本对比
        $('#todo-list').on('click', 'li', function() {
            $(this).css('text-decoration', 'line-through');
            console.log('完成事项:', $(this).text());
        });

        $('#add-item').on('click', function() {
            $('#todo-list').append('<li>新事项 ' + ($('#todo-list li').length + 1) + '</li>');
        });
        */
    </script>
</body>
</html>

Ajax请求

jQuery$.ajax 和便捷方法简化了异步请求。现代 JavaScript 提供了 fetch API,基于Promise设计,更加强大和灵活。

语法

// jQuery
$.ajax({
    url: '/api/data',
    method: 'GET',
    success: function(data) {
        console.log(data);
    },
    error: function(error) {
        console.error(error);
    }
});

// 原生 JavaScript (fetch)
fetch('/api/data')
    .then(response => {
        if (!response.ok) {
            throw new Error('网络响应异常');
        }
        return response.json(); // 或 response.text() 等
    })
    .then(data => {
        console.log(data);
    })
    .catch(error => {
        console.error('请求失败:', error);
    });

示例:Ajax请求对比
以下示例使用 fetch 发起GET请求,并处理JSON响应。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>原生JavaScript替代方案示例:Ajax (fetch)</title>
</head>
<body>
    <button id="load-data">使用 fetch 加载数据</button>
    <pre id="result">等待请求...</pre>

    <script>
        document.getElementById('load-data').addEventListener('click', function() {
            const resultEl = document.getElementById('result');
            resultEl.textContent = '请求中...';

            // 使用 fetch 发起 GET 请求 (以 GitHub API 为例)
            fetch('https://api.github.com/repos/jquery/jquery')
                .then(response => {
                    if (!response.ok) {
                        throw new Error(`HTTP 错误! 状态: ${response.status}`);
                    }
                    return response.json();
                })
                .then(data => {
                    resultEl.textContent = JSON.stringify({
                        仓库: data.name,
                        描述: data.description,
                        Star: data.stargazers_count,
                        Fork: data.forks_count
                    }, null, 2);
                })
                .catch(error => {
                    resultEl.textContent = '请求失败: ' + error.message;
                });
        });

        /* jQuery 版本对比
        $('#load-data').on('click', function() {
            $('#result').text('请求中...');
            $.ajax({
                url: 'https://api.github.com/repos/jquery/jquery',
                dataType: 'jsonp', // 注意 GitHub API 支持 JSONP 或 CORS
                success: function(data) {
                    $('#result').text(JSON.stringify({
                        仓库: data.name,
                        描述: data.description,
                        Star: data.stargazers_count,
                        Fork: data.forks_count
                    }, null, 2));
                },
                error: function() {
                    $('#result').text('请求失败');
                }
            });
        });
        */
    </script>
</body>
</html>

工具函数

jQuery 提供了许多实用工具函数,其中很多已被ES5/ES6纳入标准库。

jQuery 方法原生 JavaScript 替代方案说明
$.isArray()Array.isArray()jQuery 4.0 已移除,直接使用原生。
$.trim()String.prototype.trim()jQuery 4.0 已移除,直接调用 str.trim()
$.map()Array.prototype.map()用于数组;对于对象可用 Object.keys() 结合 map()
$.each()Array.prototype.forEach()for...of 循环遍历数组或类数组对象。
$.extend()对象展开 { ...obj1, ...obj2 }Object.assign()浅拷贝合并对象。
$.inArray()Array.prototype.indexOf()includes()检查值在数组中的位置。
$.parseJSON()JSON.parse()jQuery 4.0 已移除,直接使用原生。
$.isNumeric()!isNaN(parseFloat(n)) && isFinite(n)jQuery 4.0 已移除,需自行实现或使用 Number.isFinite() (ES6)。
$.type()typeof 结合 Object.prototype.toString.call()jQuery 4.0 已移除,用于更精确的类型判断。
$.now()Date.now()jQuery 4.0 已移除,获取当前时间戳。

示例:工具函数对比
以下示例展示了几个常用工具的原生实现。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>原生JavaScript替代方案示例:工具函数</title>
</head>
<body>
    <script>
        // 1. 数组检测
        const arr = [1, 2, 3];
        console.log('原生 Array.isArray(arr):', Array.isArray(arr)); // true

        // 2. 字符串去除两端空白
        const str = '  hello world  ';
        console.log('原生 str.trim():', str.trim()); // "hello world"

        // 3. 遍历数组
        const items = ['A', 'B', 'C'];
        items.forEach((item, index) => {
            console.log(`原生 forEach: 索引 ${index} = ${item}`);
        });

        // 4. 合并对象
        const defaults = { color: 'red', size: 10 };
        const options = { color: 'blue' };
        const settings = Object.assign({}, defaults, options); // 或 { ...defaults, ...options }
        console.log('原生 Object.assign:', settings); // { color: 'blue', size: 10 }

        // 5. 检测数值
        function isNumeric(n) {
            return !isNaN(parseFloat(n)) && isFinite(n);
        }
        console.log('原生 isNumeric("123"):', isNumeric('123')); // true
        console.log('原生 isNumeric("12.3"):', isNumeric('12.3')); // true
        console.log('原生 isNumeric("abc"):', isNumeric('abc')); // false

        // 6. JSON 解析
        const jsonStr = '{"name": "jQuery"}';
        const parsed = JSON.parse(jsonStr);
        console.log('原生 JSON.parse:', parsed.name); // jQuery

        /* jQuery 版本对比 (概念性)
        console.log('jQuery $.isArray(arr):', $.isArray(arr));
        console.log('jQuery $.trim(str):', $.trim(str));
        $.each(items, function(index, item) { console.log('jQuery each:', index, item); });
        var settings = $.extend({}, defaults, options);
        console.log('jQuery $.isNumeric("123"):', $.isNumeric('123'));
        var parsed = $.parseJSON(jsonStr);
        */
    </script>
</body>
</html>

版本变更记录

下表梳理了 jQuery 版本迭代中与原生替代方案相关的关键变化,特别是4.0.0中移除大量API,直接推动了向原生 JavaScript 的迁移。

版本变更内容与影响
1.0提供大量实用工具函数和跨浏览器兼容性处理,在当时原生API匮乏且不统一的背景下成为必需品。
1.5+引入Deferred,$.ajax 开始返回Promise兼容对象,这些功能后来被原生Promise和 fetch 借鉴。
2.x放弃对IE 6-8的支持,开始采用更现代的原生API,但保留了大部分工具函数以保持兼容性。
3.x进一步优化性能,并逐步弃用一些已有原生替代品的API,为4.0的清理做准备。
4.0重大变革:移除大量已废弃的API,包括 jQuery.isArrayjQuery.trimjQuery.typejQuery.isNumericjQuery.isFunctionjQuery.parseJSON 等。官方明确推荐使用原生 Array.isArray()String.prototype.trim()JSON.parse() 等替代。此举旨在精简库体积,鼓励开发者拥抱现代 JavaScript 标准。

浏览器兼容状态

采用原生 JavaScript 替代方案时,需关注目标浏览器对特定API的支持情况。下表列出了本章涉及的原生API的最低支持版本,可作为项目决策的参考。

浏览器最低支持版本(主要API)备注
Chrome30+fetch 在 42+ 稳定,NodeList.forEach 在 51+ 支持。
Edge12+基于Chromium的Edge(79+)支持更佳。
Firefox25+fetch 在 39+ 支持,NodeList.forEach 在 50+ 支持。
Opera18+基本与Chrome同步。
Safari7+fetch 在 10.1+ 支持,NodeList.forEach 在 10+ 支持。
Chrome Android30+跟随桌面版Chrome。
Firefox for Android25+跟随桌面版Firefox。
Opera Android18+跟随桌面版Opera。
Safari on iOS7+fetch 在 iOS 10.3+ 支持。
Samsung Internet4.0+基于Chromium,支持度较好。
WebView Android4.4+fetch 在 5.0+ (WebView 60+) 支持。
WebView on iOS7+与 iOS Safari 一致。

:对于需要支持较旧浏览器(如IE)的项目,仍需考虑使用 jQuery 或引入polyfill。但对于现代浏览器环境,原生 JavaScript 已成为可靠且高效的替代方案。理解 jQuery 的设计思想与原生API的对应关系,有助于编写更简洁、更贴近标准的代码。