Vue2 API-源码解析

目录

Vue.extend(option)

delimiters

functional 

Vue.component(id, Function | Object) 

Vue.directive( id, [definition] )

Vue.filter( id, function)

Vue.nextTick()

Vue.set()

Vue.delete(target, index/key)

Vue.compile(template)

Vue.observable(object)

provide/inject

extends、mixins


Vue.extend(option)

作用:返回一个vue子组件的构造函数

参数:创建vue实例的参数

<template>
  <div id="home">
    <div>home</div>
  </div>
</template>

<script>
import Vue from 'vue'

export default {
  name: "",
  mounted() {
    // 创建子组件构造函数 VueComponent
    var VueComponentFun = Vue.extend({
      template: "<p>{{firstName}} {{lastName}} aka {{alias}}</p>",
      data: function () {
        return {
          firstName: "Walter",
          lastName: "White",
          alias: "Heisenberg",
        };
      },
    });
    // 挂载到一个元素上。
    new VueComponentFun().$mount("#home");
  },
};
</script>

home节点被替换掉,渲染结果如下

源码:

  1. 调用Vue.prototype._init()进行数据初始化 - created周期
  2. 继承原型上的extend、mixin、use、component, directive, filter
    Vue.extend = function (extendOptions) {
        extendOptions = extendOptions || {};
        var Super = this;
        ......
        //创建子类(子组件构造函数),先调用父类的方法进行初始化
        var Sub = function VueComponent(options) {
            this._init(options);
        };
        //创建子类的原型对象
        Sub.prototype = Object.create(Super.prototype);
        Sub.prototype.constructor = Sub;

        Sub.options = mergeOptions(Super.options, extendOptions);
        Sub['super'] = Super;
        //对props属性做set、get拦截
        if (Sub.options.props) {
            initProps(Sub);
        }
        if (Sub.options.computed) {
            initComputed(Sub);
        }

        Sub.extend = Super.extend;
        Sub.mixin = Super.mixin;
        Sub.use = Super.use;
        //赋值生命周期
        ASSET_TYPES.forEach(function (type) {
            Sub[type] = Super[type];
        });
        ......

        return Sub;
    };

delimiters

作用:分隔符,定义 模板字符串的变量标识

上面的代码可改为

template: "<p @click='add'>{firstName} {lastName} aka {num}</p>",
delimiters: ['{', '}'],

functional 

作用:函数组件,没有响应式数据,也没有实例(this),使用functional:true生命,使用render生成Dom

优点: 1.使用render 函数返回虚拟节点使它们渲染的代价更小;2.不需要实例化

Vue.component('custom-component', Vue.extend({
  functional: true,
  props: {
    params: String,
  },
  render: function (h, context) {
    let props = context.props
    return h('div', { class: 'custom' }, [
      h('div', {
        domProps: {
          innerText: props.params,
        },
        class: ['custom_button'],
        on: {
          click: () => {
            console.log("click")
          },
        },
      })
    ])
  }
}))

Vue.component(id, Function | Object) 

作用:注册或获取全局组件

有下面两种方法生成组件

// 注册组件,传入一个扩展过的构造器
Vue.component('my-component', Vue.extend({ /* ... */ }))

// 注册组件,传入一个选项对象 (自动调用 Vue.extend)
Vue.component('my-component', { /* ... */ })

Vue.directive( id, [definition] )

作用:添加自定义指令,可以在绑定的元素未插入到Dom内时,判断Dom是否存在

参数:指令名称、函数

回调参数:

el:指令绑定到的元素

binding:指令接收的参数

  • value:指令绑定的对象
  • oldValue:指令绑定的对象修改之前的值
  • expression:字符串形式的指令表达式
Vue.directive('focus', {
  // 指令与元素成功绑定时调用
  bind: function (el, binding) {
  },
  // 当被绑定的元素插入到 DOM 中时……
  inserted: function (el, binding) {
  },
  // 命令所绑定的dom及数据有变化时,
  update: function (el, binding) {
  },
  // 指令所在组件的 VNode 及其子 VNode 全部更新后调用
  componentUpdated: function (el, binding) {
  },
  // 指令与元素解绑时调用
  unbind: function (el, binding) {
  }
})

 <div  v-focus="{name:a}"></div>

Vue.filter( id, function)

作用:过滤器

参数:被处理的值、接受的其他传参(多个)

//main.js
Vue.filter('capitalize', function (value, a) {
  // 被处理的值、参数...
  if (!value) return "";
  return value + a;
})

//home.vue
<template>
  <div id="home">
    <!-- 大括号绑定,页面显示11 -->
    <div>{{ a | capitalize(10) }}</div> 
    <!-- v-bind绑定 -->
    <A :pd="b | capitalize"></A>
  </div>
</template>

<script>
import A from "./A.vue";
export default {
  name: "",
  components: {
    A,
  },
  data() {
    return {
      a: 1,
    };
  },
};
</script>

源码:['component', 'directive', 'filter'] 直接返回回调函数

function initAssetRegisters(Vue) {
    ASSET_TYPES.forEach(function (type) {
        // @ts-expect-error function is not exact same type
        Vue[type] = function (id, definition) {
            if (!definition) {
                return this.options[type + 's'][id];
            }
            else {
                ......
                if (type === 'component' && isPlainObject(definition)) {
                    // @ts-expect-error
                    definition.name = definition.name || id;
                    // this.options._base = Vue构造函数,就是直接调用Vue.extend
                    definition = this.options._base.extend(definition);
                }
                if (type === 'directive' && isFunction(definition)) {
                    definition = { bind: definition, update: definition };
                }
                // 给当前实例this添加{id: definition}
                this.options[type + 's'][id] = definition;
                return definition;
            }
        };
    });
}

Vue.nextTick()

作用:在 DOM 更新循环结束之后执行延迟回调,vue修改数据时不能及时反映到页面上,需要一轮事务处理,才能获取到页面上修改过的值

参数:callback()、this

用法:

// 修改数据
vm.msg = 'Hello'
// DOM 还没有更新
Vue.nextTick(function () {
  // DOM 更新了
})

// 作为一个 Promise 使用 (2.1.0 起新增,详见接下来的提示)
Vue.nextTick()
  .then(function () {
    // DOM 更新了
  })

注:使用第二种方法时,需要在支持Promise的环境中(IE不支持)

 源码:

     如果浏览器支持Promise,则使用Promise.resolve()返回一个Promise 对象(微任务),因为微任务会等待主线程的同步任务执行完毕,再执行微任务队列。微任务队列就是下列callbacks数组,这里面会放入回调函数,如果一次同步任务中有多个nextTick,则callback中会有多个回调函数。这些回调函数会在then()回调中执行。

var p_1 = Promise.resolve();
    timerFunc = function () {
        p_1.then(flushCallbacks);

        if (isIOS)
            setTimeout(noop);
    };
function nextTick(cb, ctx) {
    // cb: 回调函数  ctx: this指向
    var _resolve;
    // 回调函数放入数组,如果短时间内多次调用nextTick,则数组中有多个回调函数
    callbacks.push(function () {
        if (cb) {
            try {
                cb.call(ctx);
            }
            catch (e) {
                handleError(e, ctx, 'nextTick');
            }
        }
        else if (_resolve) {
            _resolve(ctx);
        }
    });
    // 执行回调函数; 
    if (!pending) {
        pending = true;
        timerFunc();
    }
    // 支持.then写法
    if (!cb && typeof Promise !== 'undefined') {
        return new Promise(function (resolve) {
            _resolve = resolve;
        });
    }
}

var timerFunc; 
// 实现nextTick用了两种方法,Promise.then or MutationObserver
if (typeof Promise !== 'undefined' && isNative(Promise)) {
    // 浏览器支持Promise的情况,使用Promise
    // 创建微任务,微任务会等到主线程的代码执行完毕,再执行,所以p_1.then实现了nextTick的功能
    var p_1 = Promise.resolve();
    timerFunc = function () {
        p_1.then(flushCallbacks);

        if (isIOS)
            setTimeout(noop);
    };
    isUsingMicroTask = true;
}
else if (!isIE &&
    typeof MutationObserver !== 'undefined' &&
    (isNative(MutationObserver) ||
        // PhantomJS and iOS 7.x
        MutationObserver.toString() === '[object MutationObserverConstructor]')) {
    // Use MutationObserver where native Promise is not available,
    // e.g. PhantomJS, iOS7, Android 4.4
    var counter_1 = 1;
    var observer = new MutationObserver(flushCallbacks);
    var textNode_1 = document.createTextNode(String(counter_1));
    observer.observe(textNode_1, {
        characterData: true
    });
    timerFunc = function () {
        counter_1 = (counter_1 + 1) % 2;
        textNode_1.data = String(counter_1);
    };
    isUsingMicroTask = true;
}
else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {
    timerFunc = function () {
        setImmediate(flushCallbacks);
    };
}
else {
    timerFunc = function () {
        setTimeout(flushCallbacks, 0);
    };
}

Vue.set()

作用:向具有响应式的对象中添加property,且新的property具有响应式。在创建的过程中对该属性进行依赖收集

<template>
  <div id="home">
    <div id="customComA">{{ obj }}</div>
    <div id="customComB">{{ arr }}</div>
  </div>
</template>

<script>
import Vue from "vue";

export default {
  name: "",
  data() {
    return {
      obj: { name: "zz" },
      arr: [1, 2]
    };
  },
  mounted() {
    // 无效
     this.obj.age = 15
     this.arr[1] = 10

    // Vue.set
    Vue.set(this.obj, 'age', 15)
    Vue.set(this.obj, 1, 10)
  },
};
</script>

 源码实现:

  1. 对Array对象进行修改,对元素进行响应式化
  2. 对Object类型进行赋值,对赋值的新元素进行响应式
function set(target, key, val) {
    // obj|arr , key|index
    if (process.env.NODE_ENV !== 'production' && (isUndef(target) || isPrimitive(target))) {
        warn$2("Cannot set reactive property on undefined, null, or primitive value: ".concat(target));
    }
    if (isReadonly(target)) {
        process.env.NODE_ENV !== 'production' && warn$2("Set operation on key \"".concat(key, "\" failed: target is readonly."));
        return;
    }
    var ob = target.__ob__;
    // 对Array对象进行修改,对元素进行响应式化
    if (isArray(target) && isValidArrayIndex(key)) {
        target.length = Math.max(target.length, key);
        target.splice(key, 1, val);
        // when mocking for SSR, array methods are not hijacked
        if (ob && !ob.shallow && ob.mock) {
            observe(val, false, true);
        }
        return val;
    }
    // object修改属性值
    if (key in target && !(key in Object.prototype)) {
        console.log("obj")
        target[key] = val;
        return val;
    }
    if (target._isVue || (ob && ob.vmCount)) {
        process.env.NODE_ENV !== 'production' &&
            warn$2('Avoid adding reactive properties to a Vue instance or its root $data ' +
                'at runtime - declare it upfront in the data option.');
        return val;
    }
    // 对空值的赋值不做其他处理
    if (!ob) {
        target[key] = val;
        return val;
    }
    // object对象新增属性值
    defineReactive(ob.value, key, val, undefined, ob.shallow, ob.mock);
    if (process.env.NODE_ENV !== 'production') {
        ob.dep.notify({
            type: "add" /* TriggerOpTypes.ADD */,
            target: target,
            key: key,
            newValue: val,
            oldValue: undefined
        });
    }
    else {
        ob.dep.notify();
    }
    return val;
}

Vue.delete(target, index/key)

作用:删除属性,并触发有关dom的改变

对于Array,使用 target.splice(key, 1);

对于Object,使用 delete target[key]; 并触发监听器ob.dep.notify()

源码:

function del(target, key) {
    if (process.env.NODE_ENV !== 'production' && (isUndef(target) || isPrimitive(target))) {
        warn$2("Cannot delete reactive property on undefined, null, or primitive value: ".concat(target));
    }
    // 数组类型的直接操作
    if (isArray(target) && isValidArrayIndex(key)) {
        target.splice(key, 1);
        return;
    }
    var ob = target.__ob__;
    
    ......

    if (!hasOwn(target, key)) {
        return;
    }
    // Object类型
    delete target[key];
    if (!ob) {
        return;
    }
    // 通知删除的该元素关联的依赖
    if (process.env.NODE_ENV !== 'production') {
        ob.dep.notify({
            type: "delete" /* TriggerOpTypes.DELETE */,
            target: target,
            key: key
        });
    }
    else {
        ob.dep.notify();
    }
}

Vue.compile(template)

作用:将一个模板字符串编译成 render 函数(VNode)

//把解析的模板渲染,挂载到.home节点上
let res = Vue.compile("<div class='wrapper'>{{ msg }}</div>");
new Vue({
  data: {
    msg: "hello",
  },
  render: res.render,
  // staticRenderFns: res.staticRenderFns,
}).$mount(".home");

源码: 

var _a = createCompiler(baseOptions)

执行createCompiler函数,即createCompilerCreator函数,即执行 createCompiler函数,同时对baseCompile、compile函数进行缓存;

Vue.compile = compileToFunctions;
Vue.compile("<div class='wrapper'>{{ msg }}</div>");

1.执行createCompileToFunctionFn(compile),即compileToFunctions函数,判断缓存中是否有该模板的编译结果,如果有,取出返回;没有则执行compile函数,之后把获取到的编译结果res.render转化为函数形式,编译结果res写入缓存

2.执行compile函数,先执行baseCompile编译模板template,再在编译结果compiled上添加errors、tips(与options有关,没传入,暂不考虑)

3.执行baseCompile函数,把template模板字符串处理成ast(树状数据结构,未注入真实数据),调用generate把ast转化为render渲染函数字符串形式,返回{ast, render,staticRenderFns)

部分简略源码:

function createCompileToFunctionFn(compile) {
     // compile, 一开始就被缓存的参数
    var cache = Object.create(null);  //对解析的模板进行缓存
    return function compileToFunctions(template, options, vm) {
        /**
         * template: <div class='wrapper'><div>{{ msg }}</div></div>
         * option未传
         */
        console.log("1----compileToFunctions")
        ......
        var key = template;
        if (cache[key]) {
            return cache[key];
        }
        // compile
        var compiled = compile(template, options);
        ......
        var res = {};
        var fnGenErrors = [];
        res.render = createFunction(compiled.render, fnGenErrors);
        res.staticRenderFns = compiled.staticRenderFns.map(function (code) {
            return createFunction(code, fnGenErrors);
        });
        ......
        return (cache[key] = res);
    };
}

function createCompilerCreator(baseCompile) {
    // baseCompile, 一开始就被缓存的参数
    return function createCompiler(baseOptions) {
        // 先调用createCompiler,什么都不执行,只返回return {compile, compileToFunctions}
        function compile(template, options) {
            console.log("2----compile")
            var finalOptions = Object.create(baseOptions);
            ......
            var compiled = baseCompile(template.trim(), finalOptions);
            if (process.env.NODE_ENV !== 'production') {
                detectErrors(compiled.ast, warn);
            }
            compiled.errors = errors;
            compiled.tips = tips;
            return compiled;
        }
        return {
            compile: compile,
            compileToFunctions: createCompileToFunctionFn(compile)
        };
    };
}

var createCompiler = createCompilerCreator(
    function baseCompile(template, options) {
        console.log("3----baseCompile")
        var ast = parse(template.trim(), options);  // 把template字符串处理成树状数据结构,未注入真实数据
        var code = generate(ast, options); // code: {render, staticRenderFns}
        return {
            ast: ast,
            render: code.render, // render函数
            staticRenderFns: code.staticRenderFns
        };
});
//入口
var _a = createCompiler(baseOptions), compileToFunctions = _a.compileToFunctions;
Vue.compile = compileToFunctions;

Vue.observable(object)

作用:让一个对象可响应,返回的对象可以直接用于渲染函数和计算属性内,并且会在发生变更时触发相应的更新。也可以作为最小化的跨组件状态存储器

1.使用计算属性

<template>
  <div id="home">
    <!-- 点击可改变obj、arr, 并能响应页面 -->
    <div @click="changeObj">obj: {{ obj  }}</div>
    <div @click="changeArr">arr: {{ arr  }}</div>
  </div>
</template>

<script>
import Vue from "vue";
// 需要使用computed做中介,供页面使用
const state = Vue.observable({ arr: [1,2,3], obj: {name: 'haha', age: 10} });
console.log("state: ", state); //响应式数据

export default {
  name: "",
  data() {
    return {
    };
  },
  computed: {
    obj(){
      return state.obj
    },
    arr(){
      return state.arr
    }
  },
  methods: {
    changeObj(){
      state.obj.age++
    },
    changeArr(){
      state.arr.push(10)
    },
    pushRouter(){
      this.$router.push("/b")
    }
  },
};
</script>

2.把该步骤单独封装为文件,使用计算属性,可作为跨组件状态存储器使用 

// store.js
import Vue from "vue";
const state = Vue.observable({ arr: [1,2,3], obj: {name: 'haha', age: 10} });
export default state

//A页面
<template>
   <div>arr: {{ arr }}</div>
</template>

<script>
import state from "@/store/replaceStore.js";
export default {
  computed: {
    arr() {
      return state.arr;
    },
  },
};
</script>

源码:

function initGlobalAPI(Vue) {
  ......
  Vue.observable = function (obj) {
      observe(obj);
      return obj;
  };
  ......
}

function observe(value, shallow, ssrMockReactivity) {
  // 已经有响应式对象,直接retuen响应式对象
  if (value && hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
      return value.__ob__;
  }
  ......
  return new Observer(value, shallow, ssrMockReactivity);
}

function Observer(value, shallow, mock) {
  if (shallow === void 0) { shallow = false; }
  if (mock === void 0) { mock = false; }
  this.value = value;
  this.shallow = shallow;
  this.mock = mock;
  this.dep = mock ? mockDep : new Dep();
  this.vmCount = 0;
  // 给value添加属性{__ob__: Observer对象}, 表示该数据value已经被响应式
  def(value, '__ob__', this);
  if (isArray(value)) {
      if (!mock) {
          if (hasProto) {
              value.__proto__ = arrayMethods;
          }
          else {
              // 对数组进行拦截 
              for (var i = 0, l = arrayKeys.length; i < l; i++) {
                  var key = arrayKeys[i];
                  def(value, key, arrayMethods[key]);
              }
          }
      }
      if (!shallow) {
          this.observeArray(value);
      }
  }
  else {
     // 对每个属性进行响应式  
      var keys = Object.keys(value);
      for (var i = 0; i < keys.length; i++) {
          var key = keys[i];
          defineReactive(value, key, NO_INIITIAL_VALUE, undefined, shallow, mock);
      }
  }
}

provide/inject

作用:祖孙组件通信

provide:返回一个对象,或者一个返回对象的函数

inject:注入的字段名,可重命名

//返回一个对象
//父组件
provide: {
    msg: 'haha', //--非响应式
    name: this.name, //--简单类型,非响应式
    arr: this.arr, //--Array、Object类型,响应式
},
//子组件
inject: ["name"],

//返回一个函数
//父组件
provide: {
    name: () => this.subName, //--简单类型,响应式
},
//子组件
<template>
   <div>name: {{ name() }}</div>
</template>
inject: ["name"],

v-once

模板只渲染一次,不会根据数据的变化而重新渲染模板

<transition>

vue内部自定义组件,可以设置过渡效果

参数:

  • name,会根据name自动生成六个类名,表示不同的过渡阶段

extends、mixins

 作用:扩展另一个组件,与minxins原理类似

extends会比mixins先执行。执行顺序:extends > mixins > 组件

<template>
  <div id="home">
    <div>firstName: {{ firstName }}</div>
  </div>
</template>

<script>
export default {
  name: "",
  extends: {
    data: function () {
      return {
        firstName: "Walter"
      };
    },
    mounted() {
      // console.log("mounted: ", this);
    },
  },
};
</script>

源码:使用深搜的方法,把extends、mixin的对象扁平化到组件一级

function mergeOptions(parent, child, vm) {
    if (process.env.NODE_ENV !== 'production') {
        checkComponents(child);
    }
    if (isFunction(child)) {
        // @ts-expect-error
        child = child.options;
    }
    normalizeProps(child, vm);
    normalizeInject(child, vm);
    normalizeDirectives$1(child);

    if (!child._base) {
        if (child.extends) {
            parent = mergeOptions(parent, child.extends, vm);
        }
        if (child.mixins) {
            for (var i = 0, l = child.mixins.length; i < l; i++) {
                parent = mergeOptions(parent, child.mixins[i], vm);
            }
        }
    }
    var options = {};
    var key;
    // 映射parent的key到一级
    for (key in parent) {
        mergeField(key);
    }
     // 映射child的key(parent没有的)到一级
    for (key in child) {
        if (!hasOwn(parent, key)) {
            mergeField(key);
        }
    }
    function mergeField(key) {
        var strat = strats[key] || defaultStrat;
        options[key] = strat(parent[key], child[key], vm, key);
    }
    // 把扁平化的数据返回
    return options;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/12047.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

一文讲解系统性能分析之|iowait是什么?

我们对系统性能进行优化时&#xff0c;一般会使用 top 命令来查看系统负载和系统中各个进程的运行情况&#xff0c;从而找出影响系统性能的因素。如下图所示&#xff1a; top top 命令会输出很多系统相关的信息&#xff0c;如&#xff1a;系统负载、系统中的进程数、CPU使用率…

四十六、docker-compose部署

一个项目肯定包含多个容器&#xff0c;每个容器都手动单独部署肯定费时费力。docker-compose可以通过脚本来批量构建镜像和启动容器&#xff0c;快速的部署项目。 使用docker-compose部署主要是编写docker-compose.yml脚本。 一、项目结构 不论是Dockerfile还是docker-compo…

实验室汇报汇报汇报

1、kafka是什么 Producer&#xff1a;即生产者&#xff0c;消息的产生者&#xff0c;是消息的入口&#xff1b;Consumer&#xff1a;消费者&#xff0c;即消息的消费方&#xff0c;是消息的出口&#xff1b;Broker&#xff1a;中间代理&#xff0c;即一个broker就是一个server。…

接口优化的常见方案实战总结

一、背景 针对老项目&#xff0c;去年做了许多降本增效的事情&#xff0c;其中发现最多的就是接口耗时过长的问题&#xff0c;就集中搞了一次接口性能优化。本文将给小伙伴们分享一下接口优化的通用方案。 &#xfeff; &#xfeff; &#xfeff;&#xfeff; 二、接口优化…

设计模式-结构型模式之装饰模式

3. 装饰模式3.1. 模式动机一般有两种方式可以实现给一个类或对象增加行为&#xff1a;继承机制使用继承机制是给现有类添加功能的一种有效途径&#xff0c;通过继承一个现有类可以使得子类在拥有自身方法的同时还拥有父类的方法。但是这种方法是静态的&#xff0c;用户不能控制…

java基础——迭代器,数据结构,List,Set ,TreeSet集合,Collections工具类

迭代器&#xff0c;数据结构,List,Set ,TreeSet集合,Collections工具类 第一章 Iterator迭代器 1.1 Iterator接口 在程序开发中&#xff0c;经常需要遍历集合中的所有元素。针对这种需求&#xff0c;JDK专门提供了一个接口java.util.Iterator。 想要遍历Collection集合&…

链表基础知识

1.链表必知必会 什么是链表? 链表是一种通过指针串联在一起的线性结构&#xff0c;每一个节点由两部分组成&#xff0c;一个是数据域一个是指针域&#xff08;存放指向下一个节点的指针&#xff09;&#xff0c;最后一个节点的指针域指向null&#xff08;空指针的意思&#…

【好刊推荐】知名出版社影响因子7+被踢出SCI,投稿前如何选期刊?

今年3月Hindawi旗下的19本期刊被SCIE剔除&#xff0c;其中有一本影响因子7&#xff0c;以下从期刊各个指标方面分析一下具体原因&#xff1a; 期刊剔除&#xff1a;影响因子7 期刊简介 期刊名称&#xff1a; OXIDATIVE MEDICINE AND CELLULAR LONGEVITY ISSN / eISSN&#…

数据结构——堆和优先队列

文章目录前言堆堆的引入堆的定义堆的储存结构优先队列优先队列简介优先队列的基础操作入队出队优先队列的实现堆的应用堆排序TOP-K问题什么是TOP-K问题TOP-K问题的排序解法TOP-K问题的堆解法总结前言 堆是一个比较基础&#xff0c;且实现起来难度也不算太大的一个数据结构。而…

可选择的Elasticsearch好用的可视化客户端工具

前言 常言道&#xff1a;工欲善其事&#xff0c;必先利其器。对于我们开发和测试同学来说&#xff0c;在日常的工作中有一款趁手的工具那真实如虎添翼啊&#xff0c;工作效率可是蹭蹭蹭的往上长&#xff0c;节省下来的时间摸摸鱼该有多好啊。最近我们系统开始使用elasticsearc…

Spring注解开发

定义bean 我们先直接通过一张图来理解注解在Spring开发中如和定义bean&#xff1a; 那么我们既然加了注解&#xff0c;相当于定义了bean可是Spring的配置文件怎么知道他的存在&#xff0c;于是我们引入component-scan进行包扫描即为了让Spring框架能够扫描到写在类上的注解&…

Lego- 美团接口自动化测试实战(详细解析)

目录&#xff1a;导读 一、概述 1.1 接口自动化概述 1.2 提高 ROI 1.3 Lego 的组成 二、脚本设计 2.1 Lego 的做法 2.2 测试脚本 2.3 配置文件 三、用例设计 3.1 一些思考 3.2 Lego 接口自动化测试用例 3.3 参数化 3.4 前后置动作 3.5 执行各部分 四、网站功能 …

八百字讲清楚——BCEWithLogitsLoss二分类损失函数

BCEWithLogitsLoss是一种用于二分类问题的损失函数&#xff0c;它将Sigmoid函数和二元交叉熵损失结合在一起。 假设我们有一个大小为NNN的二分类问题&#xff0c;其中每个样本xix_ixi​有一个二元标签yi∈0,1y_i\in {0,1}yi​∈0,1&#xff0c;并且我们希望预测每个样本的概率…

Seal AppManager发布:基于平台工程理念的全新应用部署管理体验

4月12日&#xff0c;数澈软件Seal&#xff08;以下简称“Seal”&#xff09;宣布推出新一代应用统一部署管理平台 Seal AppManager&#xff0c;采用平台工程的理念&#xff0c;降低基础设施操作的复杂度为研发和运维团队提供易用、一致的应用管理和部署体验&#xff0c;进而提升…

28岁,他是如何成为上市公司测试总监的

现在的大环境下&#xff0c;各行各业都开始内卷起来&#xff0c;测试也不例外&#xff0c;企业要求也越来越高&#xff0c;“会代码”逐渐成为测试工程师的一个标签。你要想拿到一个不错的薪资&#xff0c;必不可少的一个技能—自动化测试&#xff0c;自动化测试难吗&#xff1…

【2023最新】超详细图文保姆级教程:App开发新手入门(5)

上文回顾&#xff0c;我们已经完成了一个应用的真机调试&#xff0c;本章我们来了解一下如何引入YonBuilder移动开发的&#xff08;原生&#xff09;移动插件, 并利用移动插件完成一个简单的视频播放器。 8. 「移动插件」的使用 8.1 什么是 「移动插件」&#xff1f; 用通俗…

HDLBits-Modules 题解【Verilog模块例化】(中文翻译+英文原文,可顺带学习英文)

Moudule 概念介绍 到目前为止&#xff0c;你已经熟悉了一个模块&#xff0c;它是一个通过输入和输出端口与其外部交互的电路。更大、更复杂的电路是通过将较小的模块和其他连接在一起的部分&#xff08;例如赋值语句和always块&#xff09;组合而成的更大模块来构建的。因为模…

对决:Kubernetes vs Docker Swarm - 谁才是最优秀的容器编排方案?

✅创作者&#xff1a;陈书予 &#x1f389;个人主页&#xff1a;陈书予的个人主页 &#x1f341;陈书予的个人社区&#xff0c;欢迎你的加入: 陈书予的社区 文章目录一、介绍1. 什么是Kubernetes2. 什么是Docker Swarm3. 为什么需要容器编排&#xff1f;二、 架构比较1. Kubern…

C++【栈队列(3种)反向迭代器】

文章目录一、容器适配器二、栈&#xff08;一&#xff09;栈定义&#xff08;二&#xff09;栈使用接口&#xff08;三&#xff09;栈模拟实现(1) 栈模拟实现解析(2) 栈模拟实现代码(3) 栈模拟结果三、队列&#xff08;一&#xff09;普通队列&#xff08;1&#xff09;普通队列…

30天学会《Streamlit》(3)

30学会《Streamlit》是一项编码挑战&#xff0c;旨在帮助您开始构建Streamlit应用程序。特别是&#xff0c;您将能够&#xff1a; 为构建Streamlit应用程序设置编码环境 构建您的第一个Streamlit应用程序 了解用于Streamlit应用程序的所有很棒的输入/输出小部件 第3天 - st.…