参考1.12.4版本的JQuery写了个基本实现原理:不得不说JQuery对原型的应用很巧妙。
首先讲清楚JQuery的设计目标:
- 用更简单的方式操作DOM
- 处理浏览器兼容性问题
兼容性不讲,主要是各种if else判断,纯属工作量问题。
那么JQuery到底是如何实现简单操作DOM的呢?
先来看看,JQuery是如何使用的:
- JQuery是一个函数,调用JQuery函数返回JQuery实例
- JQuery实例上绑定了很多方法操作DOM,比如css, html等
- JQuery函数上绑定了很多方法直接调用,如发送ajax请求
- 进一步用$ = JQuery,书写更简单
要清楚的知道最后的目标是什么:
调用$函数,返回一个$实例,这个$实例的原型链和正常原型链没有差别($.__proto__ === $.prototype),且该实例上绑定了很多操作DOM的方法。另外,$函数上也绑定了很多可以直接调用的方法。
以上就是目标。
<!DOCTYPE html>
<html>
<head>
<title>JQuery原理</title>
<meta charset="utf-8">
<style>
</style>
</head>
<body>
<div class='abc'>
abc
</div>
<div class='abc'>
bcd
</div>
<script>
(function(window) {
var JQuery = function(selector) {
// 创建的JQuery实例 原型就是JQuery.prototype
return new JQuery.fn.init(selector)
}
// 引入JQuery.fn有两个目的
// 1. 不然会写成JQuery.prototype.init.prototype = JQuery.prototype这种东西
// 2. 如果用一个变量替换掉JQuery.prototype 那么最后还要把这个变量也导出
// 直接绑定到JQuery上 就省的麻烦了。当然,不用JQuery.fn直接用JQuery.prototype是可行的
JQuery.fn = JQuery.prototype = {
constructor: JQuery,
init: function(selector) {
let doms = document.querySelectorAll(selector)
doms = [].slice.apply(doms)
doms.map((item, index) => this[index] = item)
return this
}
}
JQuery.fn.init.prototype = JQuery.fn
// 在JQuery上扩展方法 在JQuery.fn上扩展方法
JQuery.extend = JQuery.fn.extend = function(obj) {
for (key in obj) {
this[key] = obj[key]
}
}
JQuery.extend({
ajax: function() {
console.log('ajax')
return this
}
})
JQuery.fn.extend({
css: function() {
console.log('css')
return this
},
html: function() {
console.log('html')
return this
}
})
window.$ = JQuery
})(window)
const $d = $('.abc')
$.ajax()
$d.css()
$d.html()
// JQuery插件 就是利用提供的两个扩展方法
;(function($){
$.extend({
myAjax: function() {
console.log('myAjax')
return this
}
})
$.fn.extend({
myHtml: function() {
console.log('myHTML')
return this
}
})
})($)
$.myAjax()
$d.myHtml()
</script>
</body>
</html>
运行结果: