vue2面试题|[2024-12-5]

开题答辩终于结束了,又要开始我的前端面试学习啦!!!

1.v-model双向绑定原理

class Vue{constructor(options){this.$options = optionsthis.$watchEvent = {}if(typeof options.beforeCreate == 'function'){options.beforeCreate.bind(this)()}// 这是datathis.$data = options.datathis.proxyData()this.observe()if(typeof options.created == 'function'){options.beforeCreate.bind(this)()}if(typeof options.beforeMount == 'function'){options.beforeCreate.bind(this)()}// 这是节点this.$el = document.querySelector(options.el)// 模板渲染this.compile(this.$el)if(typeof options.mounted == 'function'){options.beforeCreate.bind(this)()}}// 1.给vue大对象赋属性,来自于data中// 2.data中的属性值和vue大对象的属性双向(劫持)proxyData(){for(let key in this.$data){Object.defineProperty(this,key,{get(){return this.$data[key]},set(val){this.$data[key] = val}})}}// 触发data中的数据发生变化来执行watch中的updateobserve(){for(let key in this.$data){let value = this.$data[key]let that = thisObject.defineProperty(this.$data,key,{get(){return value},set(val){value = valif(that.$watchEvent[key]){that.$watchEvent[key].forEach((item,index) => {item.update()})}}})}}compile(node){node.childNodes.forEach((item.index) => {// 元素节点if(item.nodeType == 1){// 判断元素节点是否绑定了@clickif(item.hasAttribute('@click')){// @click后绑定的属性值let vmKey = item.getAttribute('@click').trim()item.addEventListener('click',(event) => {this.eventFn = this.$options.methods[vmKey].bind(this)this.eventFn(event)})}// 判断元素节点是否添加了v-modelif(item.hasAttribute('v-model')){let vmKey = item.getAttribute('v-model').trim();if(this.hasOwnProperty(vmKey)){item.value = this[vmKey];}item.addEventListener('input',(event) => {this[vmKey] = item.value;})}if(item.childNodes.length>0){this.compile(item)}}// 这里是文本节点,如果有{{}}就替换成数据if(item.nodeType == 3){// 正则匹配let reg = /\{\{(.*?)\}\}/glet text = item.textContent// 给节点赋值item.textContent = text.replacce(reg,(match,vmKey) => {vmKey = vmKey.trim()if(this.hasOwnProperty(vmKey)){let watch = new Watch(this,vmKey,item,'textContent')if(this.$watchEvent[vmKey]){this.$watchEvent[vmKey].push(watch)}else{this.$watchEvent[vmKey] = []this.$watchEvent[vmKey].push(watch)}}return this.$data[vmKey]})}})}
}class Watch{constructor(vm,key,node,attr){// 对象this.vm = vm// 属性名称this.key = key// 节点this.node = node// 改变文本节点内容的字符串this.attr = attr}//执行改变(update)操作update(){this.node[this.attr] = this.vm[this.key]}}

通过Object.defineProperty劫持数据发生的改变,如果数据发生改变了(在set中进行赋值的),触发update方法进行更新节点内容({{ str }}),从而实现了数据的双向绑定原理。

2.diff算法

功能:提升性能

虚拟dom ====>  其实就是数据(把dom数据化)

<script type="text/javascript">let box = document.getElementById("box");// 第一种:操作domconsole.time('a');for(let i = 0; i <= 10000; i++){box.innerHTML = i;}console.timeEnd('a');// 第二种:数据化console.time('b');let num = 0;for(let i = 0; i <= 10000; i++){num = i;}bpx.innerHTMML = num;console.timeEnd('b');
</script>

 对于这两种方法,直接操作dom比较费时,将其数据化可以节省很多时间。

操作dom:73ms,但是数据化:0.28ms

主流:snabbdom、virtual-dom

2.1搭建环境:

npm init -y
cnpm install webpack@5 webpack-cli@3 webpack-dev-server@3 -S
cnpm install snabbdom -S
新建webpack.config.js
配置webpack.config.js

 2.2 虚拟节点和真实节点

虚拟节点:

{children: undefineddata:{}elm:h1key:undefinedsel:"h1"text:"你好h1"
}

        这是对于h1的虚拟节点,其中虚拟节点在表示时用h('h1',{},"你好h1")

        下面就是对于ul的虚拟节点:

{children:[0:{children:undefineddata:{}elm:likey:undefinedsel:"li"text:"a"}1:{...}2:{...}]data:{}elm:ulkey:undefinedsel:"ul"text:undefined}

真实节点:

<h1>你好h1</h1>

2.3 新老节点替换的规则

        1、如果新老节点不是同一个节点名称,那么就暴力删除旧的节点,创建插入新的节点

        2、只能同级比较,不能跨层比较。如果跨层那么就暴力删除旧的节点,创建插入新的节点。

        3、如果是相同节点,又分很多情况

                3.1 新节点没有children

                        如果新的节点没有children,那就证明新的节点是文本,那么直接把旧的替换成新的文本

                 3.2 新节点有children

                        新的有children,旧的也有children ===》就是diff算法的核心了

                        新的有children,旧的没有 ===》创建元素添加(把旧的内容删除清空,增加新的)

***注意:如果要提升性能,一定要加入key,key是唯一标识,在更改前后,确认是不是同一个节点。

const container = document.getElementById("container");
const btn = document.getElementById("btn");const vnode1 = h('h1',{},'你好');
patch(container,vnode1);const vnode2 = h('div',{},'hi');btn.onclick = function(){patch(vnode1,vnode2);
}

添加key,这样就可以提升性能:

const container = document.getElementById("container");
const btn = document.getElementById("btn");const vnode1 = h('ul',{},[h('li',{key:'a'},'a'),h('li',{key:'b'},'b'),h('li',{key:'c'},'c')
]);
patch(container,vnode1);const vnode2 = h('ul',{},[h('li',{key:'c'},'c'),h('li',{key:'b'},'b'),h('li',{key:'a'},'a')
]);btn.onclick = function(){patch(vnode1,vnode2);
}

3.手写diff算法-生成虚拟dom

index.js

import h from './dom/h'
let vnode1 = h('div',{},'你好吖');
console.log(vnode1)-----运行后,应该得到-----
{children:undefineddata:{}elm:undefinedkey:undefinedsel:"div"text:"你好吖"
}-------------------------------
let vnode2 = h('ul',{},[h('li',{},'a'),h('li',{},'b'),h('li',{},'c')
])
console.log(vnode2)
-----运行后,应该得到-----
{children:[0:{children:undefineddata:{}elm:likey:undefinedsel:"li"text:"a"}1:{...}2:{...}]data:{}elm:ulkey:undefinedsel:"ul"text:undefined}-------------------------------

创建h.js

import vnode from './vnode'
export default function(sel, data, params){// h函数的 第三个参数是字符串类型【意味着:他没有子元素】if( typeof params == 'string'){return vnode(undefined, data,undefined, sel, params);}else if(Array.isArray(params)){// h函数的 第三个参数是数组类型【意味着:他有子元素】let children = [];for(let item of params){children.push(item);}return vnode(children, data,undefined, sel, undefined)}
}

创建vnode.js

export default function vnode(children, data, elm, sel, text){return {children, data, elm, sel, text}
}

 4.手写diff算法-patch不是同一个节点

旧的节点为真实的节点,要将其转换为真实的虚拟节点

//index.html<div id="container">这里是container
</div>//index.jsimport h from './dom/h'
import patch from './dom/patch'
// 获取真实的dom节点
let container = document.getElementById('container');// 虚拟节点
let vnode1 = h('h1',{},''你好吖);patch(container,vnode1);
//patch.js
import vnode from './vnode'
export default function(oldVnode, newVnode){// 如果oldVnode 没有sel,就证明是非虚拟节点(就让他变成虚拟节点)if(oldVnode.sel == undefined){oldVnode = vnode([], //children{}, //dataoldVnode, //elmoldVnode.tagName.toLowerCase(), //selundefined // text)}// 判断 旧的虚拟节点 和 新的虚拟节点 是不是同一个节点if(oldVnode.sel === newVnode.sel){// 判断的条件就复杂了(很多了)}else{ // 不是同一个节点,那么就暴力删除旧的节点,创建插入新的节点// 把新的虚拟节点 创建为 dom节点let newVnodeElm = createElement(newVnode);// 获取旧的虚拟节点 .elm就是真正节点let oldVnodeElm = oldVnode.elm;// 创建新的节点if(newVnodeElm){oldVnodeElm.parentNode.insertBefore(newVnodeElm,oldVnodeElm);}// 删除旧节点oldVnodeElm.parentNode.removeChild(oldVnode);}}
// createElement.js
// vnode 为新节点,就是要创建的节点
export default function createElement(vnode){// 创建dom节点let domNode = document.createElement(vnode.sel);// 判断有没有子节点 children 是不是为undefinedif(vnode.children == undefined){domNode.innerText = vnode.text;} else if(Array.isArray(vnode.children)){// 说明内部有子节点,需要递归创建节点for(let child of vnode.children){let childDom = createElement(child);domNode.appendChild(childDom);}}// 补充elm属性vnode.elm = domNode;return domNode;
}

 5.手写diff算法-相同节点有没有children

//patch.js
import vnode from './vnode'
export default function(oldVnode, newVnode){// 如果oldVnode 没有sel,就证明是非虚拟节点(就让他变成虚拟节点)if(oldVnode.sel == undefined){oldVnode = vnode([], //children{}, //dataoldVnode, //elmoldVnode.tagName.toLowerCase(), //selundefined // text)}// 判断 旧的虚拟节点 和 新的虚拟节点 是不是同一个节点if(oldVnode.sel === newVnode.sel){// 判断的条件就复杂了(很多了)patchVnode(oldVnode,newVnode);}else{ // 不是同一个节点,那么就暴力删除旧的节点,创建插入新的节点// 把新的虚拟节点 创建为 dom节点let newVnodeElm = createElement(newVnode);// 获取旧的虚拟节点 .elm就是真正节点let oldVnodeElm = oldVnode.elm;// 创建新的节点if(newVnodeElm){oldVnodeElm.parentNode.insertBefore(newVnodeElm,oldVnodeElm);}// 删除旧节点oldVnodeElm.parentNode.removeChild(oldVnode);}}
//patchVnode.js
import createElement from './createElement'
export default function patchVnode(oldVnode,newVnode){// 判断新节点有没有childrenif(newVnode.children === undefined){// 没有子节点// 新的节点的文本 和 旧节点的文本内容是不是一样的if(newVnode.text !== oldVnode.text){oldVnode.elm.innerText = newVnode.text}}else{// 新的有子节点// 新的虚拟节点有, 旧的虚拟节点有if(oldVnode.children !== undefined && oldVnode.children.length > 0){// 最复杂的情况了,diff核心了 console.log('新旧节点都有children');}else{ // 新的虚拟节点有,旧的虚拟节点“没有”// 把旧节点的内容 清空oldVnode.elm.innerHTML = '';// 遍历新的 子节点,创建dom元素,添加到页面for( let child of newVnode.children){let childDom = createElement(child);oldVnode.elm.appendChild(childDom);}}}
}

6.diff算法核心-理论部分

每次都从1开始,不满足就依次往下执行

1.旧前 和新前

        匹配:旧前的指针++、新前的指针++

2.旧后 和新后

        匹配:旧后的指针--、新后的指针--

3.旧前 和 新后

        匹配:旧前的指针++、新后的指针--

4.旧后 和 新前

        匹配:旧后的指针--、新前的指针++

5.以上都不满足条件 ===》 查找

        新的指针++,新的添加到页面上并且新在旧的节点中有,要给旧的复制成undefined

6.创建或删除

        旧的指针指向空,新还有,新就要创建

        旧的指针不指向空,新的指针指向空,旧就要删除

注意:若对于旧的指针加或者减指向的是undefined,直接继续加或者减

 7.手写diff算法-判断前四种情况

// index.js
// 获取到了真实的dom节点
const container = document.getElementById("container");
// 获取到了按钮
const btn = document.getElementById("btn");// 虚拟节点
const vnode1 = h('ul',{},[h('li',{key:'a'},'a'),h('li',{key:'b'},'b'),h('li',{key:'c'},'c')
]);
patch(container,vnode1);const vnode2 = h('ul',{},[h('li',{key:'c'},'c'),h('li',{key:'b'},'b'),h('li',{key:'a'},'a')
]);btn.onclick = function(){patch(vnode1,vnode2);
}
// vnode.js
export default function vnode(children, data, elm, sel, text){let key = data.key;return {children, data, elm, key,sel, text}
}
//patchVnode.js
import createElement from './createElement'
import updateChildren from './updateChildren'
export default function patchVnode(oldVnode,newVnode){// 判断新节点有没有childrenif(newVnode.children === undefined){// 没有子节点// 新的节点的文本 和 旧节点的文本内容是不是一样的if(newVnode.text !== oldVnode.text){oldVnode.elm.innerText = newVnode.text}}else{// 新的有子节点// 新的虚拟节点有, 旧的虚拟节点有if(oldVnode.children !== undefined && oldVnode.children.length > 0){// 最复杂的情况了,diff核心了 console.log('新旧节点都有children');updateChildren()}else{ // 新的虚拟节点有,旧的虚拟节点“没有”// 把旧节点的内容 清空oldVnode.elm.innerHTML = '';// 遍历新的 子节点,创建dom元素,添加到页面for( let child of newVnode.children){let childDom = createElement(child);oldVnode.elm.appendChild(childDom);}}}
}
// updateChildren.js
import patchVnode from './patchVnode'
// 判断两个虚拟节点是否为同一个节点
function sameVnode(vnode1,vnode2){return vnode1.key == vnode2.key;
}
// 参数一:真实的dom节点
// 参数二:旧的虚拟节点
// 参数三:新的虚拟节点
export default (parentElm, oldCh, newCh) => {let oldStartIdx = 0;            //旧前的指针let oldEndIdx = oldCh.length-1; //旧后的指针let newStartIdx = 0;            //新前的指针let newEndIdx = newCh.length-1; //新后的指针let oldStartVnode = oldCh[oldStartIdx]; //旧前虚拟节点let oldEndVnode = oldCh[oldEndIdx];     //旧后虚拟节点let newStartVnode = newCh[newStartIdx]; //新前虚拟节点let newEndVnode = newCh[newEndIdx];     //新后虚拟节点while( oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx){if( sameVnode(oldStartVnode,newStartVnode)){// 第一种情况:旧前 和 新前console.log("1")patchVnode(oldStartVnode,newStartVnode);if(newStartVnode) newStartVnode.elm = oldStartVnode?.elm;oldStartVnode = oldCh[++oldStartIdx];newStartVnode = newCh[++newStartIdx];}else if(sameVnode(oldEndVnode,newEndVnode)){// 第二种情况:旧后 和 新后console.log("2")patchVnode(oldEndVnode,newEndVnode);if(newEndVnode) newEndVnode.elm = oldEndVnode?.elm;oldEndVnode= oldCh[--oldEndIdx];newEndVnode= newCh[--newEndIdx];}else if(sameVnode(oldStartVnode,newEndVnode)){// 第三种情况:旧前 和 新后console.log("3")patchVnode(oldStartVnode,newEndVnode);if(newEndVnode) newEndVnode.elm = oldStartVnode?.elm;// 把旧前指定的节点移动到旧后指向的节点的后面parentElm.insertBefore(oldStartVnode.elm,oldEndVnode.elm.nextSibling);oldStartVnode= oldCh[++oldStartIdx];newEndVnode= newCh[--newEndIdx];}else if(sameVnode(oldEndVnode,newStartVnode)){// 第四中情况:旧后 和 新前console.log("4")patchVnode(oldEndVnode,newStartVnode);if(newStartVnode) newStartVnode.elm = newEndVnode?.elm;// 把旧后指定的节点移动到旧前指向的节点的前面parentElm.insertBefore(oldEndVnode.elm,oldStartVnode.elm);oldEndVnode= oldCh[--oldEndIdx];newStartVnode= newCh[++newStartIdx];}else{// 第五种情况:以上都不满足条件 ===》 查找}}
}

8.手写diff算法-判断第五种情况

 

// updateChildren.js
import patchVnode from './patchVnode'
import createElement from './createElement'
// 判断两个虚拟节点是否为同一个节点
function sameVnode(vnode1,vnode2){return vnode1.key == vnode2.key;
}
// 参数一:真实的dom节点
// 参数二:旧的虚拟节点
// 参数三:新的虚拟节点
export default (parentElm, oldCh, newCh) => {let oldStartIdx = 0;            //旧前的指针let oldEndIdx = oldCh.length-1; //旧后的指针let newStartIdx = 0;            //新前的指针let newEndIdx = newCh.length-1; //新后的指针let oldStartVnode = oldCh[oldStartIdx]; //旧前虚拟节点let oldEndVnode = oldCh[oldEndIdx];     //旧后虚拟节点let newStartVnode = newCh[newStartIdx]; //新前虚拟节点let newEndVnode = newCh[newEndIdx];     //新后虚拟节点while( oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx){if( oldStartVnode == undefined){oldStartVnode = oldCh[++oldStartIdx];}if( oldEndVnode == undefined){oldEndVnode = oldCh[--oldEndIdx];}else if( sameVnode(oldStartVnode,newStartVnode)){// 第一种情况:旧前 和 新前console.log("1")patchVnode(oldStartVnode,newStartVnode);if(newStartVnode) newStartVnode.elm = oldStartVnode?.elm;oldStartVnode = oldCh[++oldStartIdx];newStartVnode = newCh[++newStartIdx];}else if(sameVnode(oldEndVnode,newEndVnode)){// 第二种情况:旧后 和 新后console.log("2")patchVnode(oldEndVnode,newEndVnode);if(newEndVnode) newEndVnode.elm = oldEndVnode?.elm;oldEndVnode= oldCh[--oldEndIdx];newEndVnode= newCh[--newEndIdx];}else if(sameVnode(oldStartVnode,newEndVnode)){// 第三种情况:旧前 和 新后console.log("3")patchVnode(oldStartVnode,newEndVnode);if(newEndVnode) newEndVnode.elm = oldStartVnode?.elm;// 把旧前指定的节点移动到旧后指向的节点的后面parentElm.insertBefore(oldStartVnode.elm,oldEndVnode.elm.nextSibling);oldStartVnode= oldCh[++oldStartIdx];newEndVnode= newCh[--newEndIdx];}else if(sameVnode(oldEndVnode,newStartVnode)){// 第四中情况:旧后 和 新前console.log("4")patchVnode(oldEndVnode,newStartVnode);if(newStartVnode) newStartVnode.elm = newEndVnode?.elm;// 把旧后指定的节点移动到旧前指向的节点的前面parentElm.insertBefore(oldEndVnode.elm,oldStartVnode.elm);oldEndVnode= oldCh[--oldEndIdx];newStartVnode= newCh[++newStartIdx];}else{// 第五种情况:以上都不满足条件 ===》 查找console.log('5');// 创建一个对象,存虚拟节点的(判断新旧有没有相同节点)const keyMap = {};for(let i = oldStartIdx;i<=oldEndIdx;i++){const key = oldCh[i]?.key;if( key ) keyMap[key] = i;}// 在旧节点中寻找新前指向的节点let idxInOld = keyMap[newStartVnode.key];// 如果有,说明数据在新旧虚拟节点中都存在if(idxInOld){const elmMove = oldCh[idxInOld];patchVnode(elMove,newStartVnode);// 处理过的节点,在旧虚拟节点的数组中,设置为undefinedoldCh[idxInOld] = undefined;parentElm.insertBefore(elMove.elm,oldStartVnode.elm);}else{// 如果没有找到 ==》 说明是一个新的节点【创建】parentElm.insertBefore( createElement(newStartVnode),oldStartVnode.elm);}// 新数据(指针) +1newStartVnode = newCh[++newStartIdx];}}// 结束while 只有两种情况 (新增和删除)// 1.oldStartIdx > oldEndIdx// 2.newStartIdx > newEndIdxif(oldStartIdx > oldEndIdx){// 进入新增操作const before = newCh[newEndIdx+1] ? newCh[newEndIdx+1].elm : null;for( let i=newStartIdx; i<=newEndIdx;i++){parentElm.insertBefore(createElement(newCh[i],before));} } else {// 进入删除操作for(let i=oldStartIdx;i<=oldEndIdx;i++){parentElm.removeChild(oldCh[i].elm);}}
}

9.谈一下MVVM框架

 web1.0时代

        文件全在一起,也就是前端和后端的代码全在一起

        问题:

                1.前端和后端都是一个人开发。(技术没有侧重点或者责任不够细分)

                2.项目不好维护

                3.html、css、js页面的静态内容没有,后端是没有办法工作的(没办法套数据)

web2.0时代

        ajax出现了,就可以:前端和后端数据分离了

        解决问题:后端不用等前端页面弄完没,后端做后端的事情(写接口),前端布局、特效、发送请求

        问题:

                1.html、css、js都在一个页面中,单个页面可能内容也比较多的(也会出现不好维护的情况)

出现前端框架MVC、MVVM

        解决问题:可以把一个“特别大”页面,进行拆分(组件化),单个组件进行维护

什么是MVVM

        Model-View-ViewModel的简写

        

view:视图【dom ==》 在页面中展示的内容】

model:模型【数据层:vue中的data数据】

viewModel:视图模型层【就是vue源码】

学了快一周的源码了,煎熬 

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AI Agent 的崛起与未来:专业模型时代的新趋势20241209

AI Agent 的崛起与未来&#xff1a;专业模型时代的新趋势 引言 &#x1f4cb; 在人工智能飞速发展的今天&#xff0c;AI Agent 正在从科幻走向现实。尽管专业大模型在垂直领域的表现令人惊艳&#xff0c;AI Agent 的整合能力和协作潜力却赋予了它独特的价值。本文将回顾 AI A…

【opencv入门教程】9.视频加载

文章选自&#xff1a; 一、VideoCapture类 用于从视频文件、图像序列或摄像头捕获视频的类。函数&#xff1a;CV_WRAP VideoCapture();brief 默认构造函数CV_WRAP explicit VideoCapture(const String& filename, int apiPreference CAP_ANY);brief 使用 API 首选项打开…

【MySQL — 数据库基础】深入解析MySQL数据库操作:创建、使用、删除及字符集管理

目录 1. 数据库的操作 1.1 显示当前的数据库 1.2 创建数据库 1.3 使用数据库 1.4 删除数据库 1.5 删除磁盘文件的原理 1.6 退出客户端 文章介绍 本文详细介绍了数据库的基本操作&#xff0c;包括显示当前数据库、创建数据库、使用数据库、删除…

k8s 优雅监控jvm及dump heap的方案探讨

背景 k8s cluster 的健康检测失败会主动重启pod&#xff0c;而大部份情况下健康检测失败都是由full gc引起的。往往发生重启时已经没有条件dump heap排查full gc的原因。 如何监控 为了避免因健康检测失败而导致的pod重启&#xff0c;我们需要实施有效的监控策略&#xff0c;这…

搭建Discuz论坛

lnmp l&#xff1a;linux操作系统 n&#xff1a;nginx前端页面 m&#xff1a;mysql数据库&#xff0c;账号密码等等都是保存在这个数据库里面 p&#xff1a;php------nginx擅长处理的是静态页面&#xff0c;页面登录账户&#xff0c;需要请求到数据库&#xff0c;通过php把动态…

SpringBoot3整合SpringMVC

一、实现过程: (1).创建程序 (2).引入依赖: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"…

移动应用开发课程第六次实验:为实验2添加登陆页面,用SQList存储好友基本信息

1、在Android Studio中&#xff0c;请在第二次实验成果的基础上完成以下实验要求。 向右滑动 请添加登录页面。在登录页面中&#xff0c;如果用户输入的用户名和密码正确&#xff0c;则跳转至如上图所示的好友列表&#xff0c;并记录用户的登录信息&#xff0c;在用户第一次登…

杨振宁大学物理视频中黄色的字,c#写程序去掉

先看一下效果&#xff1a;&#xff08;还有改进的余地&#xff09; 我的方法是笨方法&#xff0c;也比较刻板。 1&#xff0c;首先想到&#xff0c;把屏幕打印下来。c#提供了这样一个函数&#xff1a; Bitmap bmp new Bitmap(640, 480, PixelFormat.Format32bppArgb); // 创…

MaxEnt模型在物种分布模拟中如何应用?R语言+MaxEnt模型融合物种分布模拟、参数优化方法、结果分析制图与论文写作

目录 第一章 以问题导入的方式&#xff0c;深入掌握原理基础 第二章 常用数据检索与R语言自动化下载及可视化方法 第三章 R语言数据清洗与特征变量筛选 第四章 基于ArcGIS、R数据处理与进阶 第五章 基于Maxent的物种分布建模与预测 第六章 基于R语言的模型参数优化 第七…

数字图像处理(15):图像平移

&#xff08;1&#xff09;图像平移的基本原理&#xff1a;计算每个像素点的移动向量&#xff0c;并将这些像素按照指定的方向和距离进行移动。 &#xff08;2&#xff09;平移向量包括水平和垂直分量&#xff0c;可以表示为&#xff08;dx&#xff0c;dy&#xff09;&#xff…

海外的bug-hunters,不一样的403bypass

一种绕过403的新技术&#xff0c;跟大家分享一下。研究HTTP协议已经有一段时间了。发现HTTP协议的1.0版本可以绕过403。于是开始对lyncdiscover.microsoft.com域做FUZZ并且发现了几个403Forbidden的文件。 &#xff08;访问fsip.svc为403&#xff09; 在经过尝试后&#xff0…

WPF Prism 01-BootstrapperShell

Prism介绍 Prism 是一个用于在 WPF、.NET MAUI、Uno 平台和 Xamarin Forms 中构建松耦合、可维护和可测试的 XAML 应用程序的框架。每个平台都有单独的发布版本&#xff0c;并且这些版本将在独立的开发时间线上进行开发。Prism 提供了一组设计模式的实现&#xff0c;这些模式有…

计算机网络-Wireshark探索ARP

使用工具 Wiresharkarp: To inspect and clear the cache used by the ARP protocol on your computer.curl(MacOS)ifconfig(MacOS or Linux): to inspect the state of your computer’s network interface.route/netstat: To inspect the routes used by your computer.Brows…

Sketch中文版下载安装:一站式设计平台指南

Sketch&#xff0c;这个以轻量和高效著称的矢量设计工具&#xff0c;已经在全球设计领域创造了许多令人惊叹的成果。它以其矢量编辑、控件和样式等功能而闻名。而其中文版本——一站式设计平台“在线设计工具”&#xff0c;在功能全面性、中文操作环境、简洁界面以及设备兼容性…

机器学习决策树原理详解

一、引言 在当今蓬勃发展的人工智能与大数据领域&#xff0c;大模型正以前所未有的影响力改变着众多行业的格局。而决策树作为机器学习算法家族中的经典成员&#xff0c;以其简洁直观的特点和广泛的适用性&#xff0c;不仅能独立解决诸多实际问题&#xff0c;更是诸多先进大模…

Kafka怎么发送JAVA对象并在消费者端解析出JAVA对象--示例

1、在pom.xml中加入依赖 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-stream-kafka</artifactId><version>3.1.6</version></dependency> 2、配置application.yml 加入Kafk…

物品识别 树莓派 5 YOLO v5 v8 v10 11 计算机视觉

0. 要实现的效果 让树莓派可以识别身边的一些物品&#xff0c;比如电脑&#xff0c;鼠标&#xff0c;键盘&#xff0c;杯子&#xff0c;行李箱&#xff0c;双肩包&#xff0c;床&#xff0c;椅子等 1. 硬件设备 树莓派 5 raspberrypi.com/products/raspberry-pi-5/树莓派官方摄…

大数据-245 离线数仓 - 电商分析 缓慢变化维 与 拉链表 SCD Slowly Changing Dimensions

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; Java篇开始了&#xff01; 目前开始更新 MyBatis&#xff0c;一起深入浅出&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff0…

【LeetCode: 160. 相交链表 + 链表】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

从爱尔兰歌曲到莎士比亚:LSTM文本生成模型的优化之旅

上一篇&#xff1a;《再用RNN神经网络架构设计生成式语言模型》 序言&#xff1a;本文探讨了如何通过多种方法改进模型的输出&#xff0c;包括扩展数据集、调整模型架构、优化训练数据的窗口设置&#xff0c;以及采用字符级编码。这些方法旨在提高生成文本的准确性和合理性&am…