前端面试js高频手写大全

res.push(fn(arr[i]))

}

return res

}

3. reduce实现数组的map方法

Array.prototype.myMap = function(fn,thisValue){

var res = [];

thisValue = thisValue||[];

this.reduce(function(pre,cur,index,arr){

return res.push(fn.call(thisValue,cur,index,arr));

},[]);

return res;

}

var arr = [2,3,1,5];

arr.myMap(function(item,index,arr){

console.log(item,index,arr);

})

4. 手写数组的reduce方法

reduce() 方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终为一个值,是ES5中新增的又一个数组逐项处理方法

参数:

  • callback(一个在数组中每一项上调用的函数,接受四个函数:)

    • previousValue(上一次调用回调函数时的返回值,或者初始值)
  • currentValue(当前正在处理的数组元素)

  • currentIndex(当前正在处理的数组元素下标)

  • array(调用reduce()方法的数组)

  • initialValue(可选的初始值。作为第一次调用回调函数时传给previousValue的值)

function reduce(arr, cb, initialValue){

var num = initValue == undefined? num = arr[0]: initValue;

var i = initValue == undefined? 1: 0

for (i; i< arr.length; i++){

num = cb(num,arr[i],i)

}

return num

}

function fn(result, currentValue, index){

return result + currentValue

}

var arr = [2,3,4,5]

var b = reduce(arr, fn,10)

var c = reduce(arr, fn)

console.log(b)   // 24

5. 数组扁平化

数组扁平化就是把多维数组转化成一维数组

1. es6提供的新方法 flat(depth)

let a = [1,[2,3]];

a.flat(); // [1,2,3]

a.flat(1); //[1,2,3]

其实还有一种更简单的办法,无需知道数组的维度,直接将目标数组变成1维数组。depth的值设置为Infinity。

let a = [1,[2,3,[4,[5]]]];

a.flat(Infinity); // [1,2,3,4,5]  a是4维数组

2. 利用cancat

var arr1 = [1, 2, 3, [1, 2, 3, 4, [2, 3, 4]]];

function flatten(arr) {

var res = [];

for (let i = 0, length = arr.length; i < length; i++) {

if (Array.isArray(arr[i])) {

res = res.concat(flatten(arr[i])); //concat 并不会改变原数组

//res.push(…flatten(arr[i])); //扩展运算符

} else {

res.push(arr[i]);

}

}

return res;

}

flatten(arr1); //[1, 2, 3, 1, 2, 3, 4, 2, 3, 4]

6. 函数柯里化

柯里化的定义:接收一部分参数,返回一个函数接收剩余参数,接收足够参数后,执行原函数。

当柯里化函数接收到足够参数后,就会执行原函数,如何去确定何时达到足够的参数呢?

有两种思路:

  1. 通过函数的 length 属性,获取函数的形参个数,形参的个数就是所需的参数个数

  2. 在调用柯里化工具函数时,手动指定所需的参数个数

将这两点结合一下,实现一个简单 curry 函数:

/**

* 将函数柯里化

* @param fn    待柯里化的原函数

* @param len   所需的参数个数,默认为原函数的形参个数

*/

function curry(fn,len = fn.length) {

return _curry.call(this,fn,len)

}

/**

* 中转函数

* @param fn    待柯里化的原函数

* @param len   所需的参数个数

* @param args  已接收的参数列表

*/

function _curry(fn,len,…args) {

return function (…params) {

let _args = […args,…params];

if(_args.length >= len){

return fn.apply(this,_args);

}else{

return _curry.call(this,fn,len,…_args)

}

}

}

我们来验证一下:

let _fn = curry(function(a,b,c,d,e){

console.log(a,b,c,d,e)

});

_fn(1,2,3,4,5);     // print: 1,2,3,4,5

_fn(1)(2)(3,4,5);   // print: 1,2,3,4,5

_fn(1,2)(3,4)(5);   // print: 1,2,3,4,5

_fn(1)(2)(3)(4)(5); // print: 1,2,3,4,5

我们常用的工具库 lodash 也提供了 curry 方法,并且增加了非常好玩的 placeholder 功能,通过占位符的方式来改变传入参数的顺序。

比如说,我们传入一个占位符,本次调用传递的参数略过占位符, 占位符所在的位置由下次调用的参数来填充,比如这样:

直接看一下官网的例子:

接下来我们来思考,如何实现占位符的功能。

对于 lodash 的 curry 函数来说,curry 函数挂载在 lodash 对象上,所以将 lodash 对象当做默认占位符来使用。

而我们的自己实现的 curry 函数,本身并没有挂载在任何对象上,所以将 curry 函数当做默认占位符

使用占位符,目的是改变参数传递的顺序,所以在 curry 函数实现中,每次需要记录是否使用了占位符,并且记录占位符所代表的参数位置。

直接上代码:

/**

* @param  fn           待柯里化的函数

* @param  length       需要的参数个数,默认为函数的形参个数

* @param  holder       占位符,默认当前柯里化函数

* @return {Function}   柯里化后的函数

*/

function curry(fn,length = fn.length,holder = curry){

return _curry.call(this,fn,length,holder,[],[])

}

/**

* 中转函数

* @param fn            柯里化的原函数

* @param length        原函数需要的参数个数

* @param holder        接收的占位符

* @param args          已接收的参数列表

* @param holders       已接收的占位符位置列表

* @return {Function}   继续柯里化的函数 或 最终结果

*/

function _curry(fn,length,holder,args,holders){

return function(…_args){

//将参数复制一份,避免多次操作同一函数导致参数混乱

let params = args.slice();

//将占位符位置列表复制一份,新增加的占位符增加至此

let _holders = holders.slice();

//循环入参,追加参数 或 替换占位符

_args.forEach((arg,i)=>{

//真实参数 之前存在占位符 将占位符替换为真实参数

if (arg !== holder && holders.length) {

let index = holders.shift();

_holders.splice(_holders.indexOf(index),1);

params[index] = arg;

}

//真实参数 之前不存在占位符 将参数追加到参数列表中

else if(arg !== holder && !holders.length){

params.push(arg);

}

//传入的是占位符,之前不存在占位符 记录占位符的位置

else if(arg === holder && !holders.length){

params.push(arg);

_holders.push(params.length - 1);

}

//传入的是占位符,之前存在占位符 删除原占位符位置

else if(arg === holder && holders.length){

holders.shift();

}

});

// params 中前 length 条记录中不包含占位符,执行函数

if(params.length >= length && params.slice(0,length).every(i=>i!==holder)){

return fn.apply(this,params);

}else{

return _curry.call(this,fn,length,holder,params,_holders)

}

}

}

验证一下:;

let fn = function(a, b, c, d, e) {

console.log([a, b, c, d, e]);

}

let _ = {}; // 定义占位符

let fn = curry(fn,5,);  // 将函数柯里化,指定所需的参数个数,指定所需的占位符

_fn(1, 2, 3, 4, 5);                 // print: 1,2,3,4,5

fn(, 2, 3, 4, 5)(1);              // print: 1,2,3,4,5

_fn(1, _, 3, 4, 5)(2);              // print: 1,2,3,4,5

fn(1, , 3)(, 4,)(2)(5);         // print: 1,2,3,4,5

_fn(1, _, , 4)(, 3)(2)(5);        // print: 1,2,3,4,5

fn(, 2)(_, _, 4)(1)(3)(5);        // print: 1,2,3,4,5

至此,我们已经完整实现了一个 curry 函数~~

7. 实现深拷贝

浅拷贝和深拷贝的区别:

浅拷贝:只拷贝一层,更深层的对象级别的只拷贝引用

深拷贝:拷贝多层,每一级别的数据都会拷贝。这样更改拷贝值就不影响另外的对象

ES6浅拷贝方法:Object.assign(target,…sources)

let obj={

id:1,

name:‘Tom’,

msg:{

age:18

}

}

let o={}

//实现深拷贝  递归    可以用于生命游戏那个题对二维数组的拷贝,

//但比较麻烦,因为已知元素都是值,直接复制就行,无需判断

function deepCopy(newObj,oldObj){

for(var k in oldObj){

let item=oldObj[k]

//判断是数组?对象?简单类型?

if(item instanceof Array){

newObj[k]=[]

deepCopy(newObj[k],item)

}else if(item instanceof Object){

newObj[k]={}

deepCopy(newObj[k],item)

}else{  //简单数据类型,直接赋值

newObj[k]=item

}

}

}

8. 手写call, apply, bind

手写call

Function.prototype.myCall=function(context=window){  // 函数的方法,所以写在Fuction原型对象上

if(typeof this !==“function”){   // 这里if其实没必要,会自动抛出错误

throw new Error(“不是函数”)

}

const obj=context||window   //这里可用ES6方法,为参数添加默认值,js严格模式全局作用域this为undefined

obj.fn=this      //this为调用的上下文,this此处为函数,将这个函数作为obj的方法

const arg=[…arguments].slice(1)   //第一个为obj所以删除,伪数组转为数组

res=obj.fn(…arg)

delete obj.fn   // 不删除会导致context属性越来越多

return res

}

//用法:f.call(obj,arg1)

function f(a,b){

console.log(a+b)

console.log(this.name)

}

let obj={

name:1

}

f.myCall(obj,1,2) //否则this指向window

obj.greet.call({name: ‘Spike’}) //打出来的是 Spike

手写apply(arguments[this, [参数1,参数2…] ])

Function.prototype.myApply=function(context){  // 箭头函数从不具有参数对象!!!!!这里不能写成箭头函数

let obj=context||window

obj.fn=this

const arg=arguments[1]||[]    //若有参数,得到的是数组

let res=obj.fn(…arg)

delete obj.fn

return res

}

function f(a,b){

console.log(a,b)

console.log(this.name)

}

let obj={

name:‘张三’

}

f.myApply(obj,[1,2])  //arguments[1]

手写bind

this.value = 2

var foo = {

value: 1

};

var bar = function(name, age, school){

console.log(name) // ‘An’

console.log(age) // 22

console.log(school) // ‘家里蹲大学’

}

var result = bar.bind(foo, ‘An’) //预置了部分参数’An’

result(22, ‘家里蹲大学’) //这个参数会和预置的参数合并到一起放入bar中

简单版本

Function.prototype.bind = function(context, …outerArgs) {

var fn = this;

return function(…innerArgs) {   //返回了一个函数,…rest为实际调用时传入的参数

return fn.apply(context,[…outerArgs, …innerArgs]);  //返回改变了this的函数,

//参数合并

}

}

new失败的原因:

例:

// 声明一个上下文

let thovino = {

name: ‘thovino’

}

// 声明一个构造函数

let eat = function (food) {

this.food = food

console.log(${this.name} eat ${this.food})

}

eat.prototype.sayFuncName = function () {

console.log(‘func name : eat’)

}

// bind一下

let thovinoEat = eat.bind(thovino)

let instance = new thovinoEat(‘orange’)  //实际上orange放到了thovino里面

console.log(‘instance:’, instance) // {}

生成的实例是个空对象

在new操作符执行时,我们的thovinoEat函数可以看作是这样:

function thovinoEat (…innerArgs) {

eat.call(thovino, …outerArgs, …innerArgs)

}

在new操作符进行到第三步的操作thovinoEat.call(obj, …args)时,这里的obj是new操作符自己创建的那个简单空对象{},但它其实并没有替换掉thovinoEat函数内部的那个上下文对象thovino。这已经超出了call的能力范围,因为这个时候要替换的已经不是thovinoEat函数内部的this指向,而应该是thovino对象。

换句话说,我们希望的是new操作符将eat内的this指向操作符自己创建的那个空对象。但是实际上指向了thovino,new操作符的第三步动作并没有成功!

可new可继承版本

Function.prototype.bind = function (context, …outerArgs) {

let that = this;

function res (…innerArgs) {

if (this instanceof res) {

// new操作符执行时

// 这里的this在new操作符第三步操作时,会指向new自身创建的那个简单空对象{}

that.call(this, …outerArgs, …innerArgs)

} else {

// 普通bind

that.call(context, …outerArgs, …innerArgs)

}

}

res.prototype = this.prototype //!!!

return res

}

9. 手动实现new

new的过程文字描述:

  1. 创建一个空对象 obj;

  2. 将空对象的隐式原型(proto)指向构造函数的prototype。

  3. 使用 call 改变 this 的指向

  4. 如果无返回值或者返回一个非对象值,则将 obj 返回作为新对象;如果返回值是一个新对象的话那么直接直接返回该对象。

function Person(name,age){

this.name=name

this.age=age

}

Person.prototype.sayHi=function(){

console.log(‘Hi!我是’+this.name)

}

let p1=new Person(‘张三’,18)

手动实现new

function create(){

let obj={}

//获取构造函数

let fn=[].shift.call(arguments)  //将arguments对象提出来转化为数组,arguments并不是数组而是对象    !!!这种方法删除了arguments数组的第一个元素,!!这里的空数组里面填不填元素都没关系,不影响arguments的结果      或者let arg = [].slice.call(arguments,1)

obj.proto=fn.prototype

let res=fn.apply(obj,arguments)    //改变this指向,为实例添加方法和属性

//确保返回的是一个对象(万一fn不是构造函数)

return typeof res===‘object’?res:obj

}

let p2=create(Person,‘李四’,19)

p2.sayHi()

细节:

[].shift.call(arguments)  也可写成:

let arg=[…arguments]

let fn=arg.shift()  //使得arguments能调用数组方法,第一个参数为构造函数

obj.proto=fn.prototype

//改变this指向,为实例添加方法和属性

let res=fn.apply(obj,arg)

10. 手写promise(常见promise.all, promise.race)

// Promise/A+ 规范规定的三种状态

const STATUS = {

PENDING: ‘pending’,

FULFILLED: ‘fulfilled’,

REJECTED: ‘rejected’

}

class MyPromise {

// 构造函数接收一个执行回调

constructor(executor) {

this._status = STATUS.PENDING // Promise初始状态

this._value = undefined // then回调的值

this._resolveQueue = [] // resolve时触发的成功队列

this._rejectQueue = [] // reject时触发的失败队列

// 使用箭头函数固定this(resolve函数在executor中触发,不然找不到this)

const resolve = value => {

const run = () => {

// Promise/A+ 规范规定的Promise状态只能从pending触发,变成fulfilled

if (this._status === STATUS.PENDING) {

this._status = STATUS.FULFILLED // 更改状态

this._value = value // 储存当前值,用于then回调

// 执行resolve回调

while (this._resolveQueue.length) {

const callback = this._resolveQueue.shift()

callback(value)

}

}

}

//把resolve执行回调的操作封装成一个函数,放进setTimeout里,以实现promise异步调用的特性(规范上是微任务,这里是宏任务)

setTimeout(run)

}

// 同 resolve

const reject = value => {

const run = () => {

if (this._status === STATUS.PENDING) {

this._status = STATUS.REJECTED

this._value = value

while (this._rejectQueue.length) {

const callback = this._rejectQueue.shift()

callback(value)

}

}

}

setTimeout(run)

}

// new Promise()时立即执行executor,并传入resolve和reject

executor(resolve, reject)

}

// then方法,接收一个成功的回调和一个失败的回调

function then(onFulfilled, onRejected) {

// 根据规范,如果then的参数不是function,则忽略它, 让值继续往下传递,链式调用继续往下执行

typeof onFulfilled !== ‘function’ ? onFulfilled = value => value : null

typeof onRejected !== ‘function’ ? onRejected = error => error : null

// then 返回一个新的promise

return new MyPromise((resolve, reject) => {

const resolveFn = value => {

try {

const x = onFulfilled(value)

// 分类讨论返回值,如果是Promise,那么等待Promise状态变更,否则直接resolve

x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)

} catch (error) {

reject(error)

}

}

}

}

const rejectFn = error => {

try {

const x = onRejected(error)

x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)

} catch (error) {

reject(error)

}

}

switch (this._status) {

case STATUS.PENDING:

this._resolveQueue.push(resolveFn)

this._rejectQueue.push(rejectFn)

break;

case STATUS.FULFILLED:

resolveFn(this._value)

break;

case STATUS.REJECTED:

rejectFn(this._value)

break;

}

})

}

catch (rejectFn) {

return this.then(undefined, rejectFn)

}

// promise.finally方法

finally(callback) {

return this.then(value => MyPromise.resolve(callback()).then(() => value), error => {

MyPromise.resolve(callback()).then(() => error)

})

}

// 静态resolve方法

static resolve(value) {

return value instanceof MyPromise ? value : new MyPromise(resolve => resolve(value))

}

// 静态reject方法

static reject(error) {

return new MyPromise((resolve, reject) => reject(error))

}

// 静态all方法

static all(promiseArr) {

let count = 0

let result = []

return new MyPromise((resolve, reject) =>       {

if (!promiseArr.length) {

return resolve(result)

自学几个月前端,为什么感觉什么都没学到??


这种现象在很多的初学者和自学前端的同学中是比较的常见的。

因为自学走的弯路是比较的多的,会踩很多的坑,学习的过程中是比较的迷茫的。

最重要的是,在学习的过程中,不知道每个部分该学哪些知识点,学到什么程度才算好,学了能做什么。

很多自学的朋友往往都是自己去找资料学习的,资料上有的或许就学到了,资料上没有的或许就没有学到。

这就会给人一个错误的信息就是,我把资料上的学完了,估计也-就差不多的了。

但是真的是这样的吗?非也,因为很多人找的资料就是很基础的。学完了也就是掌握一点基础的东西。分享给你一份前端分析路线,你可以参考。

还有很多的同学在学习的过程中一味的追求学的速度,很快速的刷视频,写了后面忘了前面,最后什么都没有学到,什么都知道,但是什么都不懂,要具体说,也说不出个所以然。

所以学习编程一定要注重实践操作,练习敲代码的时间一定要多余看视频的时间。

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

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

相关文章

云计算考试题

Cloud ❀ 云计算-虚拟化常见的两种架构_裸金属架构和宿主型架构的区别-CSDN博客 为啥要成2 11 bcd 16 acd abcd BCD NAS为啥支持文件存储的协议 选BCD 什么是网络文件系统 选bcd 错题 选abc 选bcd 选 abd

Spring Cloud Gateway网关下的文档聚合(knife4j)

文章目录 引言I 服务发现自动聚合(discover)1.1 配置1.2 服务发现的路由聚合策略-数据来源1.3 编写动态路由实现类1.4 依赖II 其他2.1 网关动态加载swagger路由和配置2.2 无法处理 lb://URI,返回503错误。2.3 SpringBoot3 解决NoResourceFoundException: No static resource f…

让PG停摆一周的大会?2024 PGConf.dev 技术大盘点(下)

PGCon.Dev 的前身是 PGCon —— 最知名的 PostgreSQL Hacker 年度聚会&#xff0c;也可以说是决定 PostgreSQL 未来的会议。从 2007 年成立以来&#xff0c;一直都是在加拿大渥太华举办至今。 有多隆重呢&#xff1f;PG 核心组的 Peter Eisentraut 在会后做了一个统计&#xff…

建筑驱鸟设备 | 建筑专用超声波驱鸟器

从半夜的鸣叫到频繁的鸟粪污染&#xff0c;鸟类活动有时会成为城市居民不得不面对的小小困扰。通过合理的驱鸟方法&#xff0c;我们可以有效地减少鸟类对建筑物的侵扰&#xff0c;保护建筑物的完好和安全&#xff0c;同时维护城市居民的生活质量。 建筑专用超声波驱鸟器&#x…

为什么伦敦金新手不能用一小时图及以下的时间周期?

刚进入伦敦金市场的投资者&#xff0c;一般不建议使用较低的时间周期&#xff0c;如1小时图或以下。不仅如此&#xff0c;新手或者兼职投资者会被要求使用较高的时间周期交易&#xff0c;如4小时图或日线图&#xff0c;这有什么道理呢&#xff1f;下面我们就来讨论一下。 新手的…

从零开始如何学习人工智能?

说说我自己的情况&#xff1a;我接触AI的时候&#xff0c;是在研一。那个时候AlphaGo战胜围棋世界冠军李世石是大新闻&#xff0c;人工智能第一次出现我面前&#xff0c;当时就想搞清楚背后的原理以及这些技术有什么作用。 就开始找资料&#xff0c;看视频。随着了解的深入&am…

社区团购系统智慧门店物流配送系统开发,支持小程序公众号。

目录 前言&#xff1a; 一、为什么要做社区团购小程序&#xff1f; 二、怎么做一个社区团购小程序&#xff1f; 三、制作属于自己的社区团购小程序有什么好处&#xff1f; 总结&#xff1a; 前言&#xff1a; 社区团购是针对小区居民或群体开发的在线购物平台&#xff0c;…

win10手动安装stable-diffusion-webui

目录 1.python下载安装 2.git下载安装 3.stable-diffusion-webui下载 4.安装s-d-webui的依赖包&#xff08;用国内镜像提速&#xff09; 5.git下载的stable-diffusion-webui&#xff0c;依赖包提示已安装&#xff0c;但运行webui-user.bat后&#xff0c;又开始下载 6.修…

RedTail 僵尸网络积极利用新漏洞发起攻击

自从 Palo Alto 的 PAN-OS 漏洞公开披露以来&#xff0c;研究人员发现已有攻击者将该漏洞纳入武器库中。 CVE-2024-3400 2024 年 4 月 11 日&#xff0c;Palo Alto 发布公告称基于 PAN-OS 的产品中存在的 0day 漏洞已经被攻击者利用&#xff0c;安全公司 Volexity 已经发现了…

配置 python 脚本操作Excel 环境

在已装python的前提下 一、安装依赖库 pip install pandas pip install openpyxl安装完后&#xff0c;可以在 Python 中运行以下命令来查看 pandas 或 openpyxl 的安装路径&#xff1a; import pandas as pd print(pd.__path__)import openpyxl print(openpyxl.__path__)二、测…

LearnOpenGL - Android OpenGL ES 3.0 绘制纹理

系列文章目录 LearnOpenGL 笔记 - 入门 01 OpenGLLearnOpenGL 笔记 - 入门 02 创建窗口LearnOpenGL 笔记 - 入门 03 你好&#xff0c;窗口LearnOpenGL 笔记 - 入门 04 你好&#xff0c;三角形OpenGL - 如何理解 VAO 与 VBO 之间的关系LearnOpenGL - Android OpenGL ES 3.0 绘制…

光纤中的数值 2.405 是怎么一回事?

在光纤通信中,光线的传播依赖于纤芯和包层之间的折射率差异。 即,当光线从纤芯入射到界面上时,如果入射角大于临界角 θ0,将发生全反射,没有光能量透射至包层而泄漏出去,此即光纤导光原理。 反映到光纤的端面,在光纤端面的光线,当入射角必须小于光纤的孔径角 α0 ,此时…

高效管理:好用的项目管理工具推荐

在当今快速变化的商业环境中&#xff0c;高效的项目管理工具能够显著提升团队的生产力和项目的成功率&#xff0c;还能有效地跟踪项目进度。所以&#xff0c;一款优秀的项目管理工具首先要具备先进的项目管理理念&#xff0c;支持多种研发管理和项目管理方法论&#xff0c;才能…

名称申请不了商标,可以受保护不!

前几天个网友说要申请注册个商标名称&#xff0c;发来名称让普推商标知产老杨帮忙检索了下&#xff0c;发现有同名的被驳回&#xff0c;而且是做过驳回复审被驳回&#xff0c;而且是绝对理由驳回的&#xff0c;易使消费者对商品的品质等特点产生误认&#xff0c;不得作为商标使…

IntelliJ IDEA 2024 mac/win版:编程利器,智慧之选

IntelliJ IDEA 2024是一款由JetBrains精心打造的集成开发环境(IDE)&#xff0c;专为Java等编程语言量身打造&#xff0c;同时支持多种其他语言&#xff0c;为开发者提供了卓越的开发体验。 IntelliJ IDEA 2024 mac/win版获取 这款IDE凭借其出色的智能化和高效性&#xff0c;赢…

红军九大技战法

一、动态对抗&#xff0c;线上社工持续信息追踪 发起攻击前&#xff0c;发起攻击前&#xff0c;尽可能多的搜集攻击目标信息&#xff0c;做到知己知彼&#xff0c;直击目标最脆弱的地方。攻击者搜集关于目标组织的人员信息、组织架构、网络资产、技术框架及安全措施信息&#x…

java基于ssm+jsp 高校四六级报名管理系统

1前台首页功能模块 高校四六级报名管理系统&#xff0c;在系统首页可以查看首页、四六级报名、新闻资讯、我的、跳转到后台、在线客服等内容&#xff0c;如图1所示。 图1系统功能界面图 学生登录、学生注册&#xff0c;在注册页面可以填写学号、密码、姓名、学院、班级、手机、…

现货黄金应用价格行为交易所需要的环境

在现货黄金投资中&#xff0c;投资者常用价格行为交易法来分析走势。简单来说&#xff0c;这种方法就是只看K线和支撑阻力位&#xff0c;顶多加一些简单的指标&#xff0c;以此构建分析和交易的系统。由于价格行为简单易学&#xff0c;现在的投资者或多或少都在使用这个方法。但…

短视频批量下载工具源码逻辑解析(软件)

短视频批量提取第三篇关于视频提取下载的思路 一&#xff1a;概述 因为上一篇不完整&#xff0c;这里其实就是补充第二篇关于源码思路。这里不针对视频评论的提取&#xff0c;只对视频分享链接批量导入下载进行思路解析 二&#xff1a;难点 通常情况下如果直接访问详情页进行…

【稀疏三维重建】Flash3D:单张图像重建场景的GaussianSplitting

项目主页&#xff1a;https://www.robots.ox.ac.uk/~vgg/research/flash3d/ 来源&#xff1a;牛津、澳大利亚国立 提示&#xff1a; 文章目录 摘要1.引言2.相关工作3.方法3.1 背景&#xff1a;从单个图像中重建场景3.2 单目 4.实验4.14.2 跨域新视角合成4.3 域内新视图合成4.4…