Vue实现原理的简单介绍

本篇文章给大家带来的内容是关于vue实现原理的简单介绍,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

用了Vue也有两年时间了,一直以来都是只知其然,不知其所以然,为了能更好的使用Vue不被Vue所奴役,学习一下Vue底层的基本原理。

Vue官网有一段这样的介绍:当你把一个普通的JavaScript对象传给Vue实例的data选项,Vue将遍历此对象所有的属性,并使用Object.defineProperty把这些属性全部转为getter/setter。Object.defineProperty是ES5中一个无法shim的特性,这也就是为什么Vue不支持 IE8 以及更低版本浏览器。

通过这一段的介绍不难可以得出,Vue是通过Object.defineProperty对实例中的data数据做了挟持并且使用Object.defineProperty的getter/setter并对其进行处理之后完成了数据的与视图的同步。

%E7%AB%8B%E5%8D%B3%E5%AD%A6%E4%B9%A0%E2%80%9C前端免费学习笔记(深入)”;

这张图应该不会很陌生,熟悉Vue的同学如果仔细阅读过Vue文档的话应该都看到过。猜想一下Vue使用Object.defineProperty做为ViewModel,对数据进行挟持之后如果View和Model发生变化的话,就会通知其相对应引用的地方进行更新处理,完成视图的与数据的双向绑定。

下面举个例子:

html:

登录后复制

javaScript:

var obj = {};Object.defineProperty(obj,"name",{    get() {        return document.querySelector("#name").innerHTML;    },    set(val) {        document.querySelector("#name").innerHTML = val;    }})obj.name = "Aaron";

登录后复制

通过上面的代码使用Object.defineProperty对Obj对象中的name属性进行了挟持,一旦该属性发生了变化则会触发set函数执行,做出响应的操作。

扯了这么多,具体说一下Vue实现的原理。

需要数据监听器Observer,能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅者。需要指令解析器Compile,对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数。一个Watcher,作为连接Observer和Compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图。MVVM入口函数,整合以上三者,实现数据响应。

%E6%8E%A5%E4%B8%8B%E6%9D%A5%E7%9A%84%E6%96%87%E7%AB%A0%E5%B0%86%E6%B2%BF%E7%9D%80%E8%BF%99%E4%B8%AA%E6%80%9D%E8%B7%AF%E4%B8%80%E6%AD%A5%E4%B8%80%E6%AD%A5%E5%90%91%E4%B8%8B%E8%BF%9B%E8%A1%8C%EF%BC%8C%E4%BB%A5%E4%BE%BF%E5%AE%8C%E6%88%90%E4%B8%80%E4%B8%AA%E7%AE%80%E5%8D%95%E7%9A%84Vue%E7%B1%BB%EF%BC%8C%E5%AE%8C%E6%88%90%E6%95%B0%E6%8D%AE%E4%B8%8E%E8%A7%86%E5%9B%BE%E7%9A%84%E5%AE%9E%E6%97%B6%E6%9B%B4%E6%96%B0%E3%80%82

{{name}}

{{age}}

{{doubleAge}}

new QVue({ el:"#app", data:{ name:"I am test", age:12, html:"" }, created(){ console.log("开始吧,QVue"); setTimeout(() => { this.name = "测试数据,更改了么"; },2000) }, methods:{ changeName(){ this.name = "点击啦,改变吧"; this.age = 1000000; } }})

登录后复制

%E4%BB%A5%E4%B8%8A%E4%BB%A3%E7%A0%81%E5%88%99%E6%98%AF%E9%9C%80%E8%A6%81%E5%AE%8C%E6%88%90%E7%9A%84%E5%8A%9F%E8%83%BD%EF%BC%8C%E4%BF%9D%E8%AF%81%E6%89%80%E6%9C%89%E5%8A%9F%E8%83%BD%E5%85%A8%E9%83%A8%E9%83%BD%E8%83%BD%E5%AE%9E%E7%8E%B0%E3%80%82

%E9%A6%96%E5%85%88%E6%88%91%E4%BB%AC%E8%A6%81%E8%80%83%E8%99%91%E7%9A%84%E6%98%AF%EF%BC%8C%E8%A6%81%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AAVue%E7%9A%84%E7%B1%BB%EF%BC%8C%E8%AF%A5%E7%B1%BB%E6%8E%A5%E6%94%B6%E7%9A%84%E6%98%AF%E4%B8%80%E4%B8%AAoptions%E7%9A%84%E5%AF%B9%E8%B1%A1%EF%BC%8C%E4%B9%9F%E5%B0%B1%E6%98%AF%E6%88%91%E4%BB%AC%E5%9C%A8%E5%AE%9E%E4%BE%8B%E5%8C%96Vue%E7%9A%84%E6%97%B6%E5%80%99%E9%9C%80%E8%A6%81%E4%BC%A0%E9%80%92%E7%9A%84%E5%8F%82%E6%95%B0%E3%80%82

class QVue {    constructor(options){        //  缓存options对象数据        this.$options = options;        //  取出data数据,做数据响应        this.$data = options.data || {};    }}

登录后复制

%E9%80%9A%E8%BF%87%E4%B8%8A%E9%9D%A2%E7%9A%84%E4%BB%A3%E7%A0%81%E5%8F%AF%E4%BB%A5%E7%9C%8B%E5%87%BA%E4%BA%86%EF%BC%8C%E4%B8%BA%E4%BB%80%E4%B9%88%E6%88%91%E4%BB%AC%E5%8F%AF%E4%BB%A5%E5%9C%A8Vue%E5%AE%9E%E4%BE%8B%E4%B8%8A%E9%80%9A%E8%BF%87this.%24data%E6%8B%BF%E5%88%B0%E6%88%91%E4%BB%AC%E6%89%80%E5%86%99%E7%9A%84data%E6%95%B0%E6%8D%AE%E3%80%82

%E5%AF%B9%E6%95%B0%E6%8D%AE%E5%B7%B2%E7%BB%8F%E8%BF%9B%E8%A1%8C%E4%BA%86%E7%BC%93%E5%AD%98%E4%B9%8B%E5%90%8E%EF%BC%8C%E6%8E%A5%E4%B8%8B%E6%9D%A5%E8%A6%81%E5%81%9A%E7%9A%84%E4%BA%8B%E6%83%85%E5%B0%B1%E6%98%AF%E5%AF%B9%E6%95%B0%E6%8D%AE%E8%BF%9B%E8%A1%8C%E8%A7%82%E5%AF%9F%EF%BC%8C%E8%BE%BE%E5%88%B0%E6%95%B0%E6%8D%AE%E5%8F%98%E5%8C%96%E4%B9%8B%E5%90%8E%E8%83%BD%E5%A4%9F%E5%81%9A%E5%87%BA%E5%AF%B9%E8%99%9A%E6%8B%9FDom%E7%9A%84%E6%93%8D%E4%BD%9C%E3%80%82

class QVue {    constructor(options){        this.$options = options;        //  数据响应        this.$data = options.data || {};        //  监听数据变化        this.observe(this.$data);        //  主要用来解析各种指令,比如v-modal,v-on:click等指令        new Compile(options.el,this);        //  执行生命周期        if(options.created){            options.created.call(this);        }    }    // 观察数据变化    observe(value){        if(!value || typeof value !== "object"){            return;        }        let keys = Object.keys(value);        keys.forEach((key)=> {            this.defineReactive(value,key,value[key]);            //  代理data中的属性到vue实例上            this.proxyData(key);        })    }    //  代理Data    proxyData(key){        Object.defineProperty(this,key,{            get(){                return this.$data[key];            },            set(newVal){                this.$data[key] = newVal;            }        })    }    //  数据响应    defineReactive(obj,key,val){        //  解决数据层次嵌套        this.observe(val);        const dep = new Dep();        Object.defineProperty(obj, key,{            get(){                //  向管理watcher的对象追加watcher实例                //  方便管理                Dep.target && dep.appDep(Dep.target);                return val;            },            set(newVal){                if(newVal === val){                    return;                }                val = newVal;                // console.log(`${key}更新了:${newVal}`)                dep.notify();            }        })    }}

登录后复制

%E6%88%91%E4%BB%AC%E5%AF%B9data%E6%95%B0%E6%8D%AE%E4%B8%AD%E7%9A%84%E6%AF%8F%E4%B8%80%E9%A1%B9%E9%83%BD%E8%BF%9B%E8%A1%8C%E4%BA%86%E6%95%B0%E6%8D%AE%E6%8C%9F%E6%8C%81%EF%BC%8C%E5%8F%AF%E6%98%AF%E7%84%B6%E8%80%8C%E5%B9%B6%E6%B2%A1%E6%9C%89%E4%BB%80%E4%B9%88%E5%8D%B5%E7%94%A8%E5%95%8A%EF%BC%8C%E6%88%91%E4%BB%AC%E5%B9%B6%E6%B2%A1%E6%9C%89%E5%AF%B9%E7%9B%B8%E5%AF%B9%E5%BA%94%E7%9A%84%E8%99%9A%E6%8B%9Fdom%E8%BF%9B%E8%A1%8C%E6%95%B0%E6%8D%AE%E6%94%B9%E5%8F%98%EF%BC%8C%E5%BD%93%E7%84%B6%E6%88%91%E4%BB%AC%E8%82%AF%E5%AE%9A%E6%98%AF%E4%B8%8D%E8%83%BD%E6%8A%8A%E6%88%91%E4%BB%AC%E7%9A%84%E9%9C%80%E8%A6%81%E6%9B%B4%E6%94%B9%E7%9A%84%E8%99%9A%E6%8B%9Fdom%E6%93%8D%E4%BD%9C%E5%86%99%E5%9C%A8%E8%BF%99%E9%87%8C%EF%BC%8C%E7%84%B6%E8%80%8C%E5%9C%A8Vue%E4%B8%AD%E5%AF%B9%E5%85%B6Dom%E8%BF%9B%E8%A1%8C%E4%BA%86%E7%89%B9%E6%AE%8A%E7%9A%84%E5%A4%84%E7%90%86%EF%BC%8C%E6%85%A2%E6%85%A2%E7%9A%84%E5%90%91%E4%B8%8B%E7%9C%8B%E3%80%82

%E6%83%B3%E8%A6%81%E5%81%9A%E6%95%B0%E6%8D%AE%E5%93%8D%E5%BA%94%E8%A6%81%E5%81%9A%E4%B8%80%E4%B8%AA%E5%81%9A%E5%85%B7%E4%BD%93%E6%9B%B4%E6%96%B0%E7%9A%84%E7%B1%BB%E4%BD%95%E4%BB%A5%E7%94%A8%E6%9D%A5%E7%AE%A1%E7%90%86%E8%BF%99%E4%BA%9B%E8%A7%82%E5%AF%9F%E8%80%85%E7%9A%84%E7%B1%BB

//  管理watcherclass Dep {    constructor() {        //  存储        this.deps = [];    }    //  添加watcher    appDep(dep){        this.deps.push(dep);    }    //  通知所有的watcher进行更新    notify(){        this.deps.forEach((dep) => {            dep.update();        })    }}//  观察者 做具体更新class Watcher {    constructor(vm,key,cb){        //  Vue实例        this.vm = vm;        //  需要更新的key        this.key = key;        //  更新后执行的函数        this.cb = cb;        //  将当前watcher实例指定到Dep静态属性target        //  用来在类间进行通信        Dep.target = this;        //  触发getter,添加依赖        this.vm[this.key];        Dep.target = null;    }    update(){        this.cb.call(this.vm,this.vm[this.key]);    }}

登录后复制

Dep.target%20=%20this%E4%B8%8A%E9%9D%A2%E8%BF%99%E6%AE%B5%E4%BB%A3%E7%A0%81%E4%B8%80%E5%AE%9A%E8%A6%81%E6%B3%A8%E6%84%8F%EF%BC%8C%E6%98%AF%E5%90%91Dep%E7%B1%BB%E4%B8%AD%E6%B7%BB%E5%8A%A0%E4%BA%86%E4%B8%80%E4%B8%AA%E9%9D%99%E6%80%81%E5%B1%9E%E6%80%A7%E3%80%82

%E4%B8%BB%E8%A6%81%E7%94%A8%E6%9D%A5%E8%A7%A3%E6%9E%90%E5%90%84%E7%A7%8D%E6%8C%87%E4%BB%A4%EF%BC%8C%E6%AF%94%E5%A6%82v-modal%EF%BC%8Cv-on:click%E7%AD%89%E6%8C%87%E4%BB%A4%E3%80%82%E7%84%B6%E5%90%8E%E5%B0%86%E6%A8%A1%E7%89%88%E4%B8%AD%E7%9A%84%E5%8F%98%E9%87%8F%E6%9B%BF%E6%8D%A2%E6%88%90%E6%95%B0%E6%8D%AE%EF%BC%8C%E6%B8%B2%E6%9F%93view%EF%BC%8C%E5%B0%86%E6%AF%8F%E4%B8%AA%E6%8C%87%E4%BB%A4%E5%AF%B9%E5%BA%94%E7%9A%84%E8%8A%82%E7%82%B9%E7%BB%91%E5%AE%9A%E6%9B%B4%E6%96%B0%E5%87%BD%E6%95%B0%EF%BC%8C%E6%B7%BB%E5%8A%A0%E7%9B%91%E5%90%AC%E6%95%B0%E6%8D%AE%E7%9A%84%E8%AE%A2%E9%98%85%E8%80%85%EF%BC%8C%E4%B8%80%E6%97%A6%E6%95%B0%E6%8D%AE%E5%8F%91%E7%94%9F%E5%8F%98%E5%8A%A8%EF%BC%8C%E6%94%B6%E5%88%B0%E9%80%9A%E7%9F%A5%EF%BC%8C%E6%9B%B4%E6%96%B0%E8%A7%86%E5%9B%BE%E3%80%82

%E7%AE%80%E5%8D%95%E8%AF%B4%E4%B8%8B%E5%8F%8C%E5%90%91%E7%BB%91%E5%AE%9A%EF%BC%8C%E5%8F%8C%E5%90%91%E7%BB%91%E5%AE%9A%E5%8E%9F%E7%90%86%EF%BC%8C%E5%9C%A8%E7%BC%96%E8%AF%91%E7%9A%84%E6%97%B6%E5%80%99%E5%8F%AF%E4%BB%A5%E8%A7%A3%E6%9E%90%E5%87%BAv-model%E5%9C%A8%E5%81%9A%E6%93%8D%E4%BD%9C%E7%9A%84%E6%97%B6%E5%80%99%EF%BC%8C%E5%9C%A8%E4%BD%BF%E7%94%A8v-model%E5%85%83%E7%B4%A0%E4%B8%8A%E6%B7%BB%E5%8A%A0%E4%BA%86%E4%B8%80%E4%B8%AA%E4%BA%8B%E4%BB%B6%E7%9B%91%E5%90%AC%EF%BC%88input%EF%BC%89%EF%BC%8C%E6%8A%8A%E4%BA%8B%E4%BB%B6%E7%9B%91%E5%90%AC%E7%9A%84%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0%E4%BD%9C%E4%B8%BA%E4%BA%8B%E4%BB%B6%E7%9B%91%E5%90%AC%E7%9A%84%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0%EF%BC%8C%E5%A6%82%E6%9E%9Cinput%E5%8F%91%E7%94%9F%E5%8F%98%E5%8C%96%E7%9A%84%E6%97%B6%E5%80%99%E6%8A%8A%E6%9C%80%E6%96%B0%E7%9A%84%E5%80%BC%E8%AE%BE%E7%BD%AE%E5%88%B0vue%E7%9A%84%E5%AE%9E%E4%BE%8B%E4%B8%8A%EF%BC%8C%E5%9B%A0%E4%B8%BAvue%E5%B7%B2%E7%BB%8F%E5%AE%9E%E7%8E%B0%E4%BA%86%E6%95%B0%E6%8D%AE%E7%9A%84%E5%93%8D%E5%BA%94%E5%8C%96%EF%BC%8C%E5%93%8D%E5%BA%94%E5%8C%96%E7%9A%84set%E5%87%BD%E6%95%B0%E4%BC%9A%E8%A7%A6%E5%8F%91%E7%95%8C%E9%9D%A2%E4%B8%AD%E6%89%80%E6%9C%89%E4%BE%9D%E8%B5%96%E6%A8%A1%E5%9D%97%E7%9A%84%E6%9B%B4%E6%96%B0%EF%BC%8C%E7%84%B6%E5%90%8E%E9%80%9A%E7%9F%A5%E5%93%AA%E4%BA%9Bmodel%E5%81%9A%E4%BE%9D%E8%B5%96%E6%9B%B4%E6%96%B0%EF%BC%8C%E6%89%80%E4%BB%A5%E7%95%8C%E9%9D%A2%E4%B8%AD%E6%89%80%E6%9C%89%E8%B7%9F%E8%BF%99%E4%B8%AA%E6%95%B0%E6%8D%AE%E6%9C%89%E7%AE%A1%E7%9A%84%E4%B8%9C%E8%A5%BF%E5%B0%B1%E6%9B%B4%E6%96%B0%E4%BA%86%E3%80%82

class Compile {    constructor(el,vm) {        //  要遍历的宿主节点        this.$el = document.querySelector(el);        this.$vm = vm;        //  编译        if(this.$el){            //  转换宿主节点内容为片段Fragment元素            this.$fragment = this.node2Fragment(this.$el);            //  执行编译过程            this.compile(this.$fragment);            //  将编译完的HTML结果追加至宿主节点中            this.$el.appendChild(this.$fragment);        }    }    //  将宿主元素中代码片段取出来,遍历,这样做比较高效    node2Fragment(el){        const frag = document.createDocumentFragment();        //  将宿主元素中所有子元素**(搬家,搬家,搬家)**至frag中        let child;        //  如果 el.firstChild 为undefined或null则会停止循环        while(child = el.firstChild){            frag.appendChild(child);        }        return frag;    }    compile(el){        //  宿主节点下的所有子元素        const childNodes = el.childNodes;        Array.from(childNodes).forEach((node) => {            if(this.isElement(node)){                //  如果是元素                console.log("编译元素"+node.nodeName)                //  拿到元素上所有的执行,伪数组                const nodeAttrs = node.attributes;                Array.from(nodeAttrs).forEach((attr) => {                    //  属性名                    const attrName = attr.name;                     //  属性值                    const exp = attr.value;                         //  如果是指令                    if(this.isDirective(attrName)){                        //  q-text                        //  获取指令后面的内容                        const dir = attrName.substring(2);                        //  执行更新                        this[dir] && this[dir](node,this.$vm,exp);                    }                    //  如果是事件                    if(this.isEvent(attrName)){                        //  事件处理                        let dir = attrName.substring(1);    //  @                        this.eventHandler(node,this.$vm,exp,dir);                    }                })            }else if(this.isInterpolation(node)){                //  如果是插值文本                this.compileText(node);                console.log("编译文本"+node.textContent)            }            //  递归子元素,解决元素嵌套问题            if(node.childNodes && node.childNodes.length){                this.compile(node);            }        })    }    //  是否为节点    isElement(node){        return node.nodeType === 1;    }    //  是否为插值文本    isInterpolation(node){        return node.nodeType === 3 && /{{(.*)}}/.test(node.textContent);    }    //  是否为指令    isDirective(attr){        return attr.indexOf("q-") == 0;    }    // 是否为事件    isEvent(attr){        return attr.indexOf("@") == 0;    }    //  v-text    text(node,vm,exp){        this.update( node, vm, exp, "text");    }    textUpdater(node,value){        node.textContent = value;    }    //  双向绑定    //  v-model    model(node,vm,exp){        //  指定input的value属性,模型到视图的绑定        this.update(node,vm,exp,"model");        //  试图对模型的响应        node.addEventListener('input',(e) => {            vm[exp] = e.target.value;        })    }    modelUpdater(node,value){        node.value = value;    }    //  v-html    html(node,vm,exp){        this.update(node,vm,exp,"html")    }    htmlUpdater(node,value){        node.innerHTML = value;    }        //  更新插值文本    compileText(node){        let key = RegExp.$1;        this.update( node, this.$vm, key, "text");    }    //  事件处理器    eventHandler(node,vm,exp,dir){        let fn = vm.$options.methods && vm.$options.methods[exp];        if(dir && fn){            node.addEventListener(dir,fn.bind(vm));        }    }    //  更新函数 - 桥接    update(node,vm,exp,dir){        const updateFn = this[`${dir}Updater`];        //  初始化        updateFn && updateFn(node,vm[exp]);        //  依赖收集        new Watcher(vm,exp,function(value){            updateFn && updateFn(node,value);        })    }}

登录后复制

%E5%85%B6%E5%AE%9ECompile%E6%95%B4%E4%B8%AA%E7%BC%96%E8%AF%91%E8%BF%87%E7%A8%8B%EF%BC%8C%E5%B0%B1%E6%98%AF%E5%9C%A8%E5%81%9A%E4%B8%80%E4%B8%AA%E4%BE%9D%E8%B5%96%E6%94%B6%E9%9B%86%E7%9A%84%E5%B7%A5%E4%BD%9C%EF%BC%8C%E7%84%B6Vue%E7%9F%A5%E9%81%93%E6%AF%8F%E4%B8%80%E4%B8%AA%E6%8C%87%E4%BB%A4%E6%98%AF%E5%81%9A%E4%BB%80%E4%B9%88%E7%9A%84%E3%80%82%E5%B9%B6%E5%81%9A%E5%87%BA%E5%AF%B9%E5%BA%94%E7%9A%84%E6%9B%B4%E6%96%B0%E5%A4%84%E7%90%86%E3%80%82

Vue%E6%95%B4%E4%BD%93%E7%9A%84%E7%BC%96%E8%AF%91%E8%BF%87%E7%A8%8B%EF%BC%8C%E5%9B%A0%E4%B8%BAvue%E6%89%80%E7%BC%96%E5%86%99%E7%9A%84%E6%8C%87%E4%BB%A4html%E6%97%A0%E6%B3%95%E8%BF%9B%E8%A1%8C%E8%AF%86%E5%88%AB%EF%BC%8C%E9%80%9A%E8%BF%87%E7%BC%96%E8%AF%91%E7%9A%84%E8%BF%87%E7%A8%8B%E5%8F%AF%E4%BB%A5%E8%BF%9B%E8%A1%8C%E4%BE%9D%E8%B5%96%E6%94%B6%E9%9B%86%EF%BC%8C%E4%BE%9D%E8%B5%96%E6%94%B6%E9%9B%86%E4%BB%A5%E5%90%8E%E6%8A%8Adata%E4%B8%AD%E7%9A%84%E6%95%B0%E6%8D%AE%E5%92%8C%E8%A7%86%E5%9B%BE%E8%BF%9B%E8%A1%8C%E4%BA%86%E5%85%B3%E8%81%94%EF%BC%8C%E4%BA%A7%E7%94%9F%E4%BA%86%E4%BE%9D%E8%B5%96%E5%85%B3%E7%B3%BB%EF%BC%8C%E5%A6%82%E6%9E%9C%E4%BB%A5%E5%90%8E%E6%95%B0%E6%8D%AE%E6%A8%A1%E5%9E%8B%E5%8F%91%E7%94%9F%E5%8F%98%E5%8C%96%E6%88%91%E4%BB%AC%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87%E8%BF%99%E4%BA%9B%E4%BE%9D%E8%B5%96%E9%80%9A%E7%9F%A5%E8%BF%99%E4%BA%9B%E8%A7%86%E5%9B%BE%E8%BF%9B%E8%A1%8C%E6%9B%B4%E6%96%B0%EF%BC%8C%E8%BF%99%E6%98%AF%E6%89%A7%E8%A1%8C%E7%BC%96%E8%AF%91%E7%9A%84%E7%9B%AE%E7%9A%84%EF%BC%8C%E5%B0%B1%E5%8F%AF%E4%BB%A5%E5%81%9A%E5%88%B0%E6%95%B0%E6%8D%AE%E6%A8%A1%E5%9E%8B%E9%A9%B1%E5%8A%A8%E8%A7%86%E5%9B%BE%E5%8F%98%E5%8C%96%E3%80%82

“>

以上就是Vue实现原理的简单介绍的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2732122.html

(0)
上一篇 2025年3月8日 00:38:13
下一篇 2025年2月24日 03:37:25

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • JavaScript中的var和let的区别(代码示例)

    var和let都用于javascript中的函数声明,它们之间的区别是,var是函数作用域,let是块作用域。 可以说,与let相比,用var声明的变量在整个程序中都是定义的。 举个例子会更清楚地说明这种区别,如下: var的例子: 输入:…

    2025年3月8日 编程技术
    200
  • javascript中对象的介绍(附代码)

    本篇文章给大家带来的内容是关于javascript中对象的介绍(附代码),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 JavaScript 中的所有事物都是对象,并且JavaScript允许自定义对象。 对象拥有属性与方…

    编程技术 2025年3月8日
    200
  • JavaScript实现递归算法的方法介绍

    本篇文章给大家带来的内容是关于javascript实现递归算法的方法介绍,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 我们先来看一下定义。递归算法,是将问题转化为规模缩小的同类问题的子问题,每一个子问题都用一个同样的算法…

    2025年3月8日 编程技术
    200
  • jQuery的用法介绍(代码)

    本篇文章给大家带来的内容是关于jQuery的用法介绍(代码),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 代码部分 window.jQuery=function(nodeOrSelector){ let nodes={}…

    编程技术 2025年3月8日
    200
  • promise是什么?怎么用?

    本篇文章给大家带来的内容是关于Laravel多态关联的介绍(附代码),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 promise是什么 官网解释 promise 表示一个异步操作的最终结果。 翻译  ==可以将promi…

    编程技术 2025年3月8日
    200
  • vue中axios请求的封装的介绍(代码)

    本篇文章给大家带来的内容是关于vue中axios请求的封装的介绍(代码),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 1、发送请求模块目录 2、/api/url中存放的是每个模块的URL // 商品模块 product.…

    2025年3月8日
    200
  • 如何更新JavaScript中的cookie?(代码示例)

    实际上,更新cookie与替换cookie略有不同,因为我们想在cookie中放入的新值在某种程度上取决于cookie是否已经存在,如果存在,则取决于它包含什么。这意味着我们需要先读取现有的cookie,然后才能为其编写替换。 需要注意的一…

    2025年3月8日
    200
  • indexedDB存储的代码示例

    本篇文章给大家带来的内容是关于indexeddb存储的代码示例,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 indexedDB(浏览器本地存储数据库)IndexedDB 就是浏览器提供的本地数据库,它可以被网页脚本创建和…

    编程技术 2025年3月8日
    200
  • apply() 和 call() 方法有什么作用?

    本篇文章给大家带来的内容是关于apply() 和 call() 方法有什么作用?有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 每个函数都包含两个非继承而来的方法:apply()和call()。;call与apply都属于F…

    编程技术 2025年3月8日
    200
  • Javascript分号规则的知识介绍(附示例)

    本篇文章给大家带来的内容是关于javascript分号规则的知识介绍(附示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 花点时间搞清楚JS中的分号规则吧~~~不管你喜欢结尾带分号或省略分号的模式 分号允许的场景 分号…

    编程技术 2025年3月8日
    200

发表回复

登录后才能评论