封装一个简单的jQuery
jQ已过时,仅用于学习封装技巧
题目: 页面有10个class含有red的div,请给这10个div每个添加一个green类
DOM API写法
const 所有标签 = document.querySelectorAll('red')
for (let i =0; i < 所有标签.length; i++) {
const 标签 = 所有标签[i]
标签.classList.add('green')
}
jQuery 写法
jQuery.('.red').addClass('green')
$('.red').addClass('green')
$ = jQuery 是个函数 别名
$('red') 没有返回元素,而是返回能操作元素的函数 这不是闭包的作用吗?
可以用闭包实现
const api = f()
api.add()
//等价于
f().add()
经典闭包作用的例子
function f() {
let n = 0
return function add() {
n += 1
console.log(n)
}
}
const add = f()
add()//1
add()//2
思考1
f函数名只用了一次, 我们删掉f之后进行变形
const add = function () {
let n = 0
return function add() {
n += 1
console.log(n)
}
}()//这个函数为立即执行函数
add()//1
add()//2
思考2
如果f函数被调用多次,那么add1和add2相等吗
function f() {
let n = 0
return function add() {
n += 1
console.log(n)
}
}
const add1 = f() //#101
const add1 = f() //#202
console.log(add1 === add2)//false
思考3
如果除了add还需要你提供一个减一操作,怎么写
返回函数对象
function f() {
let n = 0
return {
function add() {
n += 1
console.log(n)
},
function sub() {
n -= 1
console.log(n)
}
}
}
const api = f()
add() //1
sub() //0
//解构赋值
const {add, sub} = f()
add() //1
sub() //0
简易封装
function jQuery(选择器) {
const 标签伪数组 = document.querySelectorAll(选择器)
const 标签 = Array.from(标签伪数组)
const api = {
addClass(className) {
标签数组.forEach((标签) => {
标签.classList.add(className)
})
},
removeClass(className) {
标签数组.forEach((标签) => {
标签.classList.remove(className)
})
}
}
return api
}
const $ = jQuery
思考
目前的代码是否会在多次调用 $ 时造成内存冗余
$('.red').addClass('green')
$('.red').removeClass('red')
会造成冗余,三种方案
1.把api移到外面(不好解决)
2.使用隐藏属性 + 共有属性(原型写法)
3.使用class写法
原型写法
function jQuery(选择器) {
const 标签伪数组 = document.querySelectorAll(选择器)
this.标签数组 = Array.from(标签伪数组)
}
jQuery.prototype = {
constructor: jQuery
addClass(className) {
this.标签数组.forEach((标签) => {
标签.classList.add(className)
})
}
}
const $ = jQuery
new $('.red').addClass('green')
class写法
class jQuery {
constructor(选择器) {
const 所有元素伪数组 = document.querySelectorAll(选择器)
this.所有元素 = Array.from(所有元素伪数组)
}
addClass(className) {
const {所有元素} = this // 解构赋值
for (let i = 0; i < 所有元素.length; i++) {
所有元素[i].classList.add(className)
}
}
}
const $ = jQuery
new $('.red').addClass('green')
如何不用new, 又能享受到new 的便利
最终版本
function jQuery(选择器) {
if (!(this instanceof jQuery)) {
//如果this不是jQuery创建的
//说明new没有参与进来
return new jQuery(选择器)
}
//this.标签伪数组 = document.querySelectorAll(选择器), 闭包 => 实现封装
const 标签伪数组 = document.querySelectorAll(选择器)
this.标签数组 = Array.from(标签伪数组)
}
jQuery.prototype = {
constructor: jQuery
addClass(className) {
this.标签数组.forEach((标签) => {
标签.classList.add(className)
})
}
}
const $ = jQuery
$('.red').addClass('green')