简易jQuery实现思路

简易jQuery

jQuery方式一般是$(selector).fn()

思路一

const hQuery=function(selector){

}
hQuery.prototype={
    constructor: hQuery,
    addclass:function(){
        console.log('add class')
    }
}
let $node =new hQuery()
$node.addclass() 

功能上可以实现,但每次使用需要手动创建新的实例,跟我们日常使用方法不一致,需要重新改造

思路二

想要实现如下使用办法

window.$ = hQuery
$().addClass

$()运行之后必须返回一个对象才会有addClass方法

var hQuery = function(selector) {
  return new hQuery(selector)
}

hQuery.fn = hQuery.prototype = {

  addClass: function() {
    console.log('add Class')
  }
}

window.$ = hQuery

var $node = $('div')
$node.addClass('active')

但是这样书写会报错Uncaught RangeError: Maximum call stack size exceeded,原因就是new hQuery的时候执行了hQuery函数出现循环调用.所以不能直接new hQuery,得换个方式.

思路三

不直接new hQuery,那么我们再给原型添加一个方法

var hQuery = function(selector) {
  return new hQuery.fn.init(selector)
}

hQuery.fn = hQuery.prototype = {
  init: function() {
    console.log(this)
  },

  addClass: function() {
    console.log(this)
    console.log('add Class')
  }
}
window.$=hQuery
$('div').addClass

执行hQuery,返回new一个新函数得到的对象(这个对象是init函数的实例),这个新函数放hQuery的原型对象里面,但是运行之后会报如下错误VM121:16 Uncaught TypeError: $(...).addClass is not a function,原因是返回的新对象没有addClass属性;
ps:注意引擎会首先寻找init上面有没有addClass属性,没有的话会寻找init原型(init.prototype)上有没有addClass属性

思路四

var hQuery = function(selector) {
  return hQuery.fn.init(selector)
}

hQuery.fn = hQuery.prototype = {
  init: function() {
    console.log(this)
    return this
  },

  addClass: function() {
    console.log(this)
    console.log('add Class')
  }
}

window.$ = hQuery

$('div').addClass('active')

没创建新对象,共用hQuery.prototype

console.log( $('div') === $('span') )
换种写法, 这时候不报错了,但也不符合我们的需求。$()得到的结果是同一个对象。为什么需要创建新的对象?因为js对象是引用类型,如果共用对象,那么我们修改其中其中的属性会影响到其他使用这个对象的变量

思路五

var hQuery = function(selector) {
  return new hQuery.fn.init(selector)
}

hQuery.fn = hQuery.prototype = {
  init: function() {
    console.log(this)
  },
  addClass: function() {
    console.log(this)
    console.log('add Class')
  }
}
hQuery.fn.init.prototype=hQuery.fn//核心代码
window.$=hQuery
$('div').addClass

基本雏形框架基本完成;

类数组对象

  • $(selector)返回一个类数组对象,类似于{0:node0,1:node1,length:2}
  • 对init函数重构
  let nodes=document.querySelectorAll(selector);
      nodes.forEach((node,index)=>{
        this[index]=node;
      })
  this.length=nodes.length;

原型添加方法

我们后续会对原型添加方法,直接在原型上添加方法有一定隐患:例如修改了其他已经定义的方法,尤其是多人协作的过程中
我们为原型上添加一个方法,用于随时给原型添加,而不必回到一开始定义原型时的方法

 extend:function(obj){
     for (let key in obj){
       this[key]=obj;
     }

为原型添加方法示例

 hQuery.fn.extend({
    get:function(){
      console.log('get')
    } 
  })

addClass方法

一开始使用 Object.values()获取类数组对象dom节点,但是有一个问题,我们为类数组对象添加了length属性,这样便利的时候会获取到length属性,这个属性显然是没有classList属性的(就是个数字),我们当然可以使用判断把它过滤掉

  Object.values(this).forEach(node=>{ 
        if(typeof(node)!=='number'){
          node.classList.add(cls)  
        }     
      })

改用array.from实现

Array.from(this).forEach(node => node.classList.add(cls))

完整代码

const hQuery = function(selector) {
    return new hQuery.fn.init(selector)
  }
  
  hQuery.fn = hQuery.prototype = {
    init: function(selector) {
      let nodes=document.querySelectorAll(selector);
      nodes.forEach((node,index)=>{
        this[index]=node;//设置新对象属性

      })
      this.length=nodes.length;//设置新对象属性:length
      console.log('hahah')
      // return nodes
    },
    addClass: function(cls) {
      console.log('add Class')
      console.log(this)
      
      console.log(Array.from(this))
      Object.values(this).forEach(node=>{ 
        if(typeof(node)!=='number'){
          node.classList.add(cls)  
        }
             
      })
      // Array.from(this).forEach(node => node.classList.add(cls))
      // return this;
      

    },
    extend:function(obj){
     for (let key in obj){
       this[key]=obj;
     }
    }
  }

  hQuery.fn.init.prototype=hQuery.fn//核心代码
  window.$=hQuery;
  hQuery.fn.extend({
    get:function(){
      console.log('get')
    } 
  })

  $('.demo').addClass('red')
  $('.demo').addClass('yellow')

你可能感兴趣的:(简易jQuery实现思路)