今天我尝试用 JS 来实现 jQuery 中最简单的 API:addClass,removeClass,一共有三种写法:
第一种是使用闭包,代码如下:
//使用闭包实现
function Jquery(selector) {
//获取所有元素
const allElements = document.querySelectorAll(selector);
//把所有元素这个类数组转换成数组
const elements = Array.from(allElements);
// return 操作元素的方法
return {
//添加类名
addClass(className) {
elements.forEach((item) => {
item.classList.add(className);
});
},
//删除类名
removeClass(className) {
elements.forEach((item) => {
item.classList.remove(className);
});
},
};
}
//把地址给暴露出去
const $ = Jquery;
//使用
const btn = document.querySelector("#click");
btn.addEventListener("click", () => {
$(".red").addClass("green");
});
使用闭包的时候让我想到了一个问题?
如果只找到一个元素,为什么还要用数组呢?
为了统一处理,减少 if else
//一个或多个都可以搞掂
const api = {
addClass(className) {
x.forEach((标签) => {
标签.classList.add(className)
})
}
//这段代码和上面的意思差不多几乎一样. 只不过单独判断了下 其实完全没有必要
const api = {
addClass(className) {
if (x instanceof Array) {
x.forEach((标签) => {
标签.classList.add(className)
})
} else {
x.classList.add(className)
}
}
第二个问题: 目前的代码是否会在多次调用 $ 时造成内存冗余?
内存图表示的话是会造成内存冗余的呢,例如图下:
此图使用ipad 所画. 直接是用手画的. 见谅
按照调用栈内存图表示的话, 每次 (".ikun").addClass("basketball") 又会在内存中开辟新的内存存放 对应的函数.
结论:
会冗余,三种方案 1.把 api 移动到外面(不好解决) 2.使用隐藏属性 + 共有属性(原型写法) 3. 使用 class 写法
第二种是使用构造函数(或者说原型),代码如下:
// 使用原型的方式实现
function Jquery(selector) {
//获取所有元素
//自有属性
//判断 如果this 的实例不是 jquery 就帮用户 new Jquery
if (!(this instanceof Jquery)) {
return new Jquery(selector);
}
this.elements = Array.from(document.querySelectorAll(selector));
}
//原型上的方法
Jquery.prototype = {
//构造函数
constructor: Jquery,
//添加类名
addClass(className) {
this.elements.forEach((item) => {
item.classList.add(className);
});
},
//删除类名
removeClass(className) {
this.elements.forEach((item) => {
item.classList.remove(className);
});
},
};
const $ = Jquery;
//使用
const btn = document.querySelector("#click");
btn.addEventListener("click", () => {
new $(".red").addClass("green");
new $(".red").addClass("blue");
});
第三种是使用类,代码如下:
//使用class实现;
class Jquery {
constructor(selector) {
//获取所有元素
//自有属性
//new.target指向构造函数
this.elements = Array.from(document.querySelectorAll(selector));
}
//添加类名
addClass(className) {
this.elements.forEach((item) => {
item.classList.add(className);
});
}
//删除类名
removeClass(className) {
this.elements.forEach((item) => {
item.classList.remove(className);
});
}
}
const $ = Jquery;
//使用
const btn = document.querySelector("#click");
btn.addEventListener("click", () => {
new $(".red").addClass("green");
new $(".red").addClass("blue");
});