简化版自己实现jQuery及this、arguments、闭包、原型链

简化版自己实现jQuery

== 与===

参考博文为什么推荐使用 === 不推荐 ==
尽量不要用 == 规则太复杂

image.png

用===只需要注意两点,1.NaN===NaN,false,2.所有对象===也都是false,因为地址不一样.

image.png

自己写jQuery与用jQuery

mydemo预览
index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title><!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title>jQuery-Study</title>
            <script src="01_myjQuery1.js"></script>
            <script src="https://code.jquery.com/jquery-3.1.0.js"></script>
            <style>
                .red {
                    color: red;
                }

                .blue {
                    color: blue;
                }

                .big {
                    font-size: larger;
                }

                .green {
                    color: green;
                }

                .pink {
                    color: pink;
                }
                .yellow{
                    color: yellow;
                }
            </style>
        </head>
<body>

<ul>
    <li id="item1">这是li1</li>
    <li id="item2">这是li2</li>
    <li id="item3">这是li3</li>
    <li id="item4">这是li4</li>
    <li id="item5">这是li5</li>
    <li id="item6">这是li6</li>
    <li id="item7">这是li7</li>
    <li id="item8">这是li8</li>
</ul>

<button id="x">x</button>
<ol id="ol2">
    <li id="i1">1</li>
    <li id="i2">2</li>
    <li id="i3">3</li>
    <li id="i4">4</li>
    <li id="i5">5</li>
</ol>
</body>
<script>
    console.log('直接使用');
    console.log(getSiblings(item1));

    console.log('直接使用');
    addClass(item2,{a:true,xxx:false,c:true});
    console.log(item2);
</script>
<script src="UseJquery.js"></script>
</html>

01_myjQuery1.js

// 得到兄妹结点
//传入的参数是一个节点,返回兄妹结点的数组
function getSiblings(node) {
    var allSilings = node.parentNode.children;
    var siblingsArray = {length:0};
    for (let i = 0; i < allSilings.length; i++) {
        if (allSilings[i]!==node){
            siblingsArray[siblingsArray.length] = allSilings[i];
            siblingsArray.length++;
        }
    }
    return siblingsArray;
}
//添加或删除class
//传入的第一个参数是结点,第二个参数是对象, 这个对象里是key:value,key就是要操作的class,value判断操作类型,true添加,false删除
function addClass(node,object){
    for (let key in object){
        //对象调用方法的两种方式:
        // obj.f()
        // obj['f']()

        var methodName;

        methodName = object[key] ? 'add':'remove';
        node.classList[methodName](key);

        /*上面两句代码相当于
        if (object[key]) {
            node.classList.add(key);
        }else {
            node.classList.remove(key);
        }*/
    }
}
window.mydom = {};
mydom.getSiblings = getSiblings;
mydom.addClass = addClass;//命名空间,常用的设计或者组合就叫做设计模式.哈希,数组,都是一种设计模式
//所以jQuery就是这样来的,jQuery就是一个命名空间,里面有很多函数.

// 命名空间作用:1.方便识别库,2.如果都放在window里,可能会覆盖别的库,所以命名空间是为了防止覆盖别的函数

window.onload = function () {
// 测试


    // 如何直接使用item3.addclass()?,item3.getSiblings()?
    // 方法一:给原型链加公有属性公有方法,但是有缺点,容易覆盖
    Node.prototype.getSiblings = function () {
        var allSilings = this.parentNode.children;//谁调用这个函数,this就是谁
        var siblingsArray = {length:0};
        for (let i = 0; i < allSilings.length; i++) {
            if (allSilings[i]!==this){
                siblingsArray[siblingsArray.length] = allSilings[i];
                siblingsArray.length++;
            }
        }
        return siblingsArray;
    }
    let item3 = document.getElementById('item3');
    // console.log(item3.getSiblings.call(item3));如果用cal.第一个参数就是函数里的this,如果不用call(),那么this就自动变成了item3
    console.log(' 方法一:');
    console.log(item3.getSiblings());//测试成功

    Node.prototype.addClass = function (object) {
        for (let key in object){
            var methodName;
            methodName = object[key] ? 'add':'remove';
            this.classList[methodName](key);
        }
    }
    // item3.addClass.call(item3,{a:true,xxx:false,c:true});;如果用call.第一个参数就是函数里的this,如果不用call(),那么this就自动变成了item3
    console.log(' 方法一:');
    item3.addClass.call(item3,{a:true,xxx:false,c:true});
    // item3.addClass({a:true,xxx:false,c:true});
    console.log(item3);//测试成功


    // 如何直接使用item3.addclass()?,item3.getSiblings()?
    // 方法二:因为方法一在原型中添加函数容易覆盖,所以自己做一个类似的Node出来
    var Node2 = function (node) {// 将要操作的结点传进去,然后返回一个对象,这个对象里给添加了有操作这个节点方法,所以对象.方法就可以实现操作了,而不需要mydom.addclass(item3,...)这样了
        return{
            getSiblings: function () {
                var allSilings = node.parentNode.children;
                var siblingsArray = {length:0};
                for (let i = 0; i < allSilings.length; i++) {
                    if (allSilings[i]!==node){
                        siblingsArray[siblingsArray.length] = allSilings[i];
                        siblingsArray.length++;
                    }
                }
                return siblingsArray;
            },
            addClass:function (object) {
                for (let key in object){

                    var methodName;

                    methodName = object[key] ? 'add':'remove';
                    node.classList[methodName](key);

                }
            }
        }
    }
    let item4 = document.getElementById('item4');

    var item4obj = Node2(item4);

    console.log(' 方法二:');
    console.log(item4obj.getSiblings());//测试成功

    console.log(' 方法二:');
    item4obj.addClass({a:true,xxx:false,c:true});
    console.log(item4);//测试成功

    // 改为jQuery
    var jQuery = function (nodeOrSelector) {//将Node2改为jQuery,jQuery可以根据选择器去找到对应的元素
        var node;
        if(typeof nodeOrSelector==="string"){
            node = document.querySelector(nodeOrSelector);
        }else {
            node = nodeOrSelector;
        }
        return{
            getSiblings: function () {
                var allSilings = node.parentNode.children;
                var siblingsArray = {length:0};
                for (let i = 0; i < allSilings.length; i++) {
                    if (allSilings[i]!==node){
                        siblingsArray[siblingsArray.length] = allSilings[i];
                        siblingsArray.length++;
                    }
                }
                return siblingsArray;
            },
            addClass:function (object) {
                for (let key in object){

                    var methodName;

                    methodName = object[key] ? 'add':'remove';
                    node.classList[methodName](key);

                }
            }
        }
    }
    let item5 = document.getElementById('item5');

    var $item5 = jQuery(item5);
    console.log(' 改为jQuery方法:');
    console.log($item5.getSiblings());

    console.log(' 改为jQuery方法:');
    $item5.addClass({red:true,xxx:false,c:true});
    console.log(item5);//测试成功
    var child3 = jQuery('ul>li:nth-child(3)');
    child3.addClass({blue:true});


    // jQuery操作多个节点
    var jQueryS = function (nodeOrSelector) {
        var node = {};
        if (typeof nodeOrSelector ==='string'){
            var temp = document.querySelectorAll(nodeOrSelector);//先用querySelectorAll获取这个伪数组
            for (let i = 0; i < temp.length; i++) {
                node[i] = temp[i];
            }
            node.length = temp.length;//将伪数组净化,净化成只有0123值和length的伪数组

        } else if(nodeOrSelector instanceof Node){// 如果是node,也将其转化成伪数组
            node[0] =nodeOrSelector;
            node.length = 1;
        }
        node.getSiblings = function () {

        };
        node.addClass = function (classesArray) {//传入class数组,给选择的多个节点都加上数组中class
            classesArray.forEach(value=>{
                for (let i = 0; i < node.length; i++) {
                    node[i].classList.add(value);
                }
            })
        }
        node.getTexts = function () {
            var texts=[];
            for (let i = 0; i < node.length; i++) {
                texts.push(node[i].textContent);
            }
            return texts;
        }
        node.setTexts = function (text) {
            for (let i = 0; i < node.length; i++) {
                node[i].textContent = text;
            }
        }

        //set和get合并
        node.text = function (text) {
            if (text===undefined){
                var texts=[];
                for (let i = 0; i < node.length; i++) {
                    texts.push(node[i].textContent);
                }
                return texts;
            }else{
                for (let i = 0; i < node.length; i++) {
                    node[i].textContent = text;
                }
            }
        }
        return node;
    }

    var allNodes = jQueryS('ul>li:nth-child(even)');//偶数孩子
    allNodes.addClass(['big','green']);
    console.log(allNodes.getTexts());
    console.log(allNodes.text());
    // console.log(allNodes.text(1));//测试成功

    //总结:jQuery的作用就是将选择其选择的元素放到一个对象里,这个对象里有01234标序,代表每一个选择的元素,有length代表所有元素加起来总共的长度,有各种方法,addclass,gettext等等.就是反悔了这样一个hash
};

UseJquery.js

var $nodes  = $('ul>li:nth-child(even)');//注意$nodesjQuery声明的变量前面要加一个$,防止混淆,因为jQuery声明的变量只能用jQuery的api,不能用dom的api.
console.log($nodes);
x.onclick = function () {
    $nodes.toggleClass('pink');//toggle,开关,切换
    // console.log(1);
}

var colorArray = ['blue','yellow','red','pink','big']
var $nodes2 = $('#ol2>li');
$nodes2.addClass(function (index,currentClass) {
    return colorArray[index];//ol里面的每一个li加了'blue','yellow','red','pink','big'这几个属性
})
//https://www.jquery123.com/addClass/

this 和 arguments

f.call(asThis, input1,input2)

其中 asThis 会被当做 this[input1,input2] 会被当做 arguments
禁止使用 f(input1, input2),因为学会 .call 才能理解 this

this 和 arguments

function f(){
    'use strict'
    console.log(this)
    console.log(arguments)
    return undefined
}
f.call(1,2,3) // this 为 1,arguments 为 [2,3]

this 的值到底是什么?一次说清楚---方应杭
this定义:this是call的第一个参数.
this定义:this是call的第一个参数.
this定义:this是call的第一个参数.
「每日一题」JS中的闭包是什么?---方应杭

关于原型链:
「每日一题」什么是 JS原型链?---方应杭

JavaScript 世界万物诞生记

image.png

dom就是一个命名的空间,命名的所属对象
命名空间作用:1.方便识别库,2.如果都放在window里,可能会覆盖别的库,所以命名空间是为了防止覆盖别的函数

函数库:特定种类的API
jQueryMobil已经过时,不要学

jQuery的原型
测试代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.0.js"></script>
    <script>
        console.log($.prototype)
        console.log($.prototype.__proto__)
        console.log($.prototype.__proto__ === Object.prototype)//继承自Object
    </script>
</head>
<body>
    
</body>
</html>
image.png
image.png

Jquery的原型继承自 Object

image.png
image.png

自己实现JQuery例子

window.jQuery = function(nodeOrSelector) {
  let nodes = {};
  if (typeof nodeOrSelector === 'string') {
    let temp = document.querySelectorAll(nodeOrSelector)
    for (let i = 0; i < temp.length; i++) {
      nodes[i] = temp[i]
    }
    nodes.length = temp.length
  } else if (nodeOrSelector instanceof Node) {
    nodes = {
      0: nodeOrSelector,
      length: 1
    }
  }

  nodes.addClass = function(...classes) {
    classes.forEach(value=>{
      for(let i=0;i<nodes.length;i++){
        nodes[i].classList.add(value)
      }
    })
  }
  nodes.getText = function(){
    var texts = []
    for(let i=0;i<nodes.length;i++){
      texts.push(nodes[i].textContent)
    }
    return texts;
  }
  nodes.setText = function(text){
    for(let i=0;i<nodes.length;i++){
      nodes[i].textContent = text
    }
  }
  nodes.text = function(text){
    console.log(this)
    if(text){
      this.setText(text)
    }else{
      return this.getText();
    }
  }

  return nodes;
}

window.$  = jQuery

var $div = $('div')
$div.addClass('red')
$div.setText('hi') 

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,657评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,662评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,143评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,732评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,837评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,036评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,126评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,868评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,315评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,641评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,773评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,859评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,584评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,676评论 2 351