用 JS 封装一个库的基本思路

201 阅读1分钟

今天我尝试用 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)
      }
    }

第二个问题: 目前的代码是否会在多次调用 $ 时造成内存冗余?

内存图表示的话是会造成内存冗余的呢,例如图下:

image.png 此图使用ipad 所画. 直接是用手画的. 见谅

按照调用栈内存图表示的话, 每次 (".red").addClass("green");都会重新走一遍这个内存图的表现形式.那下次(".red").addClass("green"); 都会重新走一遍这个内存图的表现形式. 那下次 (".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");

});