深入理解JavaScript数组

深入理解JavaScript数组:玩转数据结构

  • 前言
  • 数组的基础知识
    • 什么是数组
    • 如何创建一个数组
    • 如何访问数组元素
  • 数组的常用操作
    • 数组的长度 length
    • 更改数组项
    • 数组的遍历
    • 数组类型的检测
    • 数组的添加和删除元素(头尾操作 push()、pop()、unshift()、shift())
    • 数组常用方法 splice()、slice()
    • 数组常用方法 join()和split()方法
      • 数组的合并方法 concat()
      • 数组的置反方法 reverse()
      • indexof()和includes()方法
      • 数组的排序 sort()
      • 关于数组在ES6中的增强
  • 遍历相关算法
  • 数组去重和随机样本
  • 冒泡排序
  • 二维数组
  • 基本类型值和引用类型值
  • 浅克隆和深克隆
    • 浅克隆
    • 深克隆
  • 全篇重要知识点

前言

在现代Web开发中,JavaScript数组是不可或缺的一部分。它们是存储和操作数据的强大工具,可以应用于各种场景,从简单的列表到复杂的数据结构。然而,尽管它们是如此常见,但很多开发人员对于JavaScript数组的真正潜力却知之甚少。本文旨在帮助读者深入了解JavaScript数组,解锁它们的全部潜力,并学习如何以更有效的方式利用它们。

数组的基础知识

什么是数组

数组(Array),顾名思义,用来存储一组相关的值,从而方便进行求和、计算平均数、逐项遍历等操作。
每种高级编程语言中都有数组,它是非常重要的一种数据结构。

如何创建一个数组

方法1、定义一个数组非常的简单,只需要使用方括号[]即可

var arr1 = ['A','B','C','D']; //打印信息: ['A', 'B', 'C', 'D']
// 方法一最常见最简单

方法2、数组还可以这样定义:

var arr2 = new Array('A','B','C','D'); //打印信息: ['A', 'B', 'C', 'D']

方法3:

var arr3 = new Array(4);   //打印信息:[empty × 4]

如何访问数组元素

在这里插入图片描述
在这里插入图片描述
JavaScript规定,访问数组中不存在的项会返回undefined,不会报错

数组的常用操作

数组的长度 length

数组的length属性表示它的长度

var arr = ['A','B','C','D'];
console.log(arr.length);  // 打印信息: 4

数组最后一项的下标是数组的长度减1 arr[arr.length - 1]

更改数组项

数组并不是只读的,我们可以修改它其中任何项的值

 var arr = [2, 6, 7, 3];arr[1]++;arr[2] = 0;console.log(arr);  //[2, 7, 0, 3]

如果更改的数组项超过了length - 1 ,则会创造这项

 var arr = [2, 6, 7, 3];arr[6] = 4;console.log(arr);  //[2, 6, 7, 3, empty × 2, 4]

数组的遍历

数组的最大的优点就是方便遍历

  var arr = [2, 6, 7, 3];for (var i = 0; i < arr.length; i++) {console.log(arr[i]);}

数组类型的检测

  • 数组用typeof 检测结果是object
  • Array.isArray()方法(兼容到IE8)可以用来检测数组
  var arr = [2, 6, 7, 3];console.log(typeof (arr));  //objectconsole.log(Array.isArray(arr));  //true
  • 鸭式辨型 检测方法
    JavaScript 中的鸭式辨型(Duck Typing)是一种动态类型检查方法,它不关心对象的实际类型,而是关注对象是否具有特定的属性和方法。这种方法的核心思想是,如果某个对象具有和“鸭子”相似的行为(比如像鸭子一样会走、游泳、嘎嘎叫),那么它就可以被视为“鸭子”。

在 JavaScript 中,进行鸭式辨型的方法主要有两种:

  1. 检查对象的属性或方法是否存在:

    function canQuackAndFly(obj) {return typeof obj.quack === 'function' && typeof obj.fly === 'function';
    }const duck = {quack() {console.log('Quack!');},fly() {console.log('Flying!');}
    };const notADuck = {quack: 'I can quack, but not really',fly: 'I can fly, but just a little'
    };console.log(canQuackAndFly(duck));    // true
    console.log(canQuackAndFly(notADuck)); // false
    
  2. 使用 instanceof 运算符:

    function Duck() {this.quack = function() {console.log('Quack!');};this.fly = function() {console.log('Flying!');};
    }const duck = new Duck();
    const notADuck = {};console.log(duck instanceof Duck);    // true
    console.log(notADuck instanceof Duck); // false
    

这两种方法都是基于对象的行为来判断对象的类型。鸭式辨型在 JavaScript 中很常见,因为 JavaScript 是一种动态类型语言,对象的类型可以在运行时改变,因此更关注对象的行为而不是它们的类型。

数组的添加和删除元素(头尾操作 push()、pop()、unshift()、shift())

在这里插入图片描述

数组常用方法 splice()、slice()

splice() 方法用于替换数组中的指定项
在这里插入图片描述
slice()

  • slice() 方法用于得到子数组,类似于字符串的slice()方法
  • slice(a,b)截取的子数组从下标为a的项开始,到下标为b(但不包括下标为b的项)结束
  • slice(a,b)方法不会更改原有数组
  • slice()如果不提供第二个参数,则表示从指定项开始,提取所有后续所有项作为子数组
  • slice()方法的参数允许为负数,表示数组的倒数第几项

数组常用方法 join()和split()方法

数组的join()方法可以使数组转为字符串;字符串的split()方法可以使字符串转为数组。
在这里插入图片描述
join()
join()的参数表示以什么字符作为连接符,如果留空则默认以逗号分隔,如同调用tostring()方法
在这里插入图片描述

splict() 注意:splict是字符串的方法
split()的参数表示以什么字符拆分字符串,一般不能留空
在这里插入图片描述
字符串和数组更多相关性
字符串也可以使用方括号内写下标的形式,访问某个字符等价于charAt()方法
在这里插入图片描述
字符串的一些算法问题有时候会转换为数组解决

数组的合并方法 concat()

concat()方法,可以合并连结多个数组
在这里插入图片描述

concat()方法 不会改变原数组

数组的置反方法 reverse()

reverse()方法用来将一个数组中的全部项顺序置反
在这里插入图片描述
题目:如何把 'ABCDEFG’置反

 var s = 'ABCDEFG'
console.log(s.split('').reverse().join(''));

indexof()和includes()方法

index0f()方法的功能是搜索数组中的元素,并返回它所在的位置,如果元素不存在,则返回-1

const beasts = ['ant', 'bison', 'camel', 'duck', 'bison'];
console.log(beasts.indexOf('bison'));
// Expected output: 1

includes()方法的功能是判断一个数组是否包含一个指定的值,返回布尔值

const array1 = [1, 2, 3];
console.log(array1.includes(2));
// Expected output: true

数组的排序 sort()

数组有sort()方法可以用于数组排序,但是涉及到函数的相关知识,在函数进行介绍。
快速了解:sort()方法
除内置排序方法外,还有一些排序算法:冒泡排序稍后介绍,快速排序在函数介绍。

关于数组在ES6中的增强

数组在ES6中新增了较多新的方法,快速了解:
ES6(ECMAScript 2015)为 JavaScript 带来了许多强大的新特性,其中也包括对数组的增强。以下是一些 ES6 中数组增强的主要特性:

  1. 扩展运算符(Spread Operator):扩展运算符用于展开数组,可以在函数调用/数组字面量中方便地展开数组元素。例如:

    const arr1 = [1, 2, 3];
    const arr2 = [4, 5, 6];
    const combined = [...arr1, ...arr2]; // [1, 2, 3, 4, 5, 6]
    
  2. 解构赋值(Destructuring Assignment):解构赋值允许将数组(或对象)的元素赋值给多个变量。例如:

    const [a, b, c] = [1, 2, 3];
    console.log(a); // 1
    console.log(b); // 2
    console.log(c); // 3
    
  3. Array.from() 方法:Array.from() 方法用于将类似数组或可迭代对象转换为真正的数组。例如:

    const str = 'hello';
    const chars = Array.from(str); // ['h', 'e', 'l', 'l', 'o']
    
  4. Array.of() 方法:Array.of() 方法用于创建一个具有可变数量参数的新数组实例,而不考虑参数的数量或类型。例如:

    const arr = Array.of(1, 'two', 3.14, [4, 5]);
    console.log(arr); // [1, 'two', 3.14, [4, 5]]
    
  5. find() 和 findIndex() 方法:这两个方法用于在数组中查找元素,find() 返回第一个满足条件的元素,而 findIndex() 返回第一个满足条件的元素的索引。例如:

    const numbers = [1, 2, 3, 4, 5];
    const evenNumber = numbers.find(num => num % 2 === 0); // 2
    const evenIndex = numbers.findIndex(num => num % 2 === 0); // 1
    
  6. includes() 方法:includes() 方法用于判断数组是否包含某个元素,返回布尔值。例如:

    const array = [1, 2, 3, 4, 5];
    console.log(array.includes(3)); // true
    console.log(array.includes(6)); // false
    

这些特性的引入极大地提升了 JavaScript 中数组的处理和操作的灵活性和便利性。

遍历相关算法

题目:求数组中每一项的总和

var scoreArr = [1, 2, 3]for (var i = 0, sum = 0; i < scoreArr.length; i++) {sum += scoreArr[i]}console.log(sum);

题目:求数组项的最大值和最小值

        var scoreArr = [1, 2, 3]var max = scoreArr[0]var min = scoreArr[0]for (var i = 0; i < scoreArr.length; i++) {if (max > scoreArr[i]) {max = scoreArr[i]}if (min < scoreArr[i]) {min = scoreArr[i]}}console.log(max, min);

数组去重和随机样本

题目:去掉数组中的重复项

        var scoreArr = [1, 2, 3, 3, 2, 2, 4];//思路:准备一个空结果数组,遍历原数组,如果遍历到的项不在结果数组中,则推入结果数组var arr = [];for (var i = 0; i < scoreArr.length; i++) {if (!arr.includes(scoreArr[i])) {arr.push(scoreArr[i])}}console.log(arr);

题目:请随机从原数组中取3项
思路:准备一个空结果数组,遍历原数组,随机选择一项,推入结果数组,并且将这项删除

 var arr = [1, 2, 3, 4, 5];var result = [];//遍历数组for (var i = 0; i < 3; i++) {//随机选择一项的下标,数组的下标 0~ arr.length -1 ;//之前学习过一个random的公式,[a,b]区间的随机数是parseInt(Math.random()*(b-a+1))+a;var n = parseInt(Math.random() * arr.length);//把这项推入结果数组result.push(arr[n]);//删除这项,防止重复被随机到arr.splice(n, 1);}console.log(result);

冒泡排序

  • 冒泡排序是一个著名的排序算法,也是在面试时非常爱考察的算法
  • 冒泡排序的核心思路是一趟一趟地进行多次项的两两比较每次都会将最小的元素排好位置,如同水中的气泡上浮一样
  • 4个数字,共需要比较3趟,比较次数为3+2+1=6次
  • n个数字,共需要比较n-1趟,比较次数为n(n-1)/2次
  var arr = [6, 9, 2, 1, 8, 5, 4];//一趟一趟比较,趟数序号就是ifor (var i = 1; i < arr.length; i++) {//内层循环负责两两比较for (var j = arr.length - 1; j >= i; j--) {//判断项的大小if (arr[j] < arr[j - 1]) {var temp = arr[j];arr[j] = arr[j - 1];arr[j - 1] = temp;}}}console.log(arr);   //[1, 2, 4, 5, 6, 8, 9]
//方法二得到同样的结果:
function compareNumbers(a, b) {return a - b;
}
console.log(arr.sort(compareNumbers));    //[1, 2, 4, 5, 6, 8, 9]

二维数组

在JavaScript中,二维数组是指一个数组中包含了其他数组作为其元素的数组。换句话说,它是一个数组的数组,每个元素都是一个数组。二维数组在 JavaScript 中是很常见的数据结构,用于表示二维表格或矩阵等数据结构。

例如,一个简单的二维数组可以表示一个包含行和列的矩阵:

var matrix = [[1, 2, 3],[4, 5, 6],[7, 8, 9]
];

这个二维数组 matrix 包含了3个子数组,每个子数组代表矩阵中的一行。可以通过索引访问其中的元素,例如 matrix[0][0] 表示矩阵的第一行第一列的元素,其值为 1。

二维数组在 JavaScript 中通常用于表示二维的数据结构,比如游戏地图、表格数据、图像数据等。对于多维数据的操作,通常需要嵌套循环来遍历访问。

基本类型值和引用类型值

在JavaScript中,基本类型值和引用类型值是两种不同的数据类型,它们在内存中的存储方式和操作行为有所不同。

  1. 基本类型值
    • JavaScript中的基本类型值包括字符串string、数字number、布尔值boolean、null和undefined
    • 基本类型值存储在栈内存中,每个变量都有自己的内存空间,它们的值直接存储在变量访问的位置。
    • 当你将一个基本类型值赋给另一个变量时,会创建一个新的独立的副本,修改其中一个变量的值不会影响另一个变量。
let a = 5;
let b = a; // 基本类型值的复制
b = 10;
console.log(a); // 输出: 5
console.log(b); // 输出: 10
  1. 引用类型值
    • 引用类型值包括对象object、数组array和函数function
    • 引用类型值存储在堆内存中,变量中存储的是对它们的引用(即内存地址)。
    • 当你将一个引用类型值赋给另一个变量时,实际上是将相同的引用复制给了另一个变量,它们指向同一个对象,因此修改其中一个变量会影响到另一个变量。
let obj1 = { name: 'Alice' };
let obj2 = obj1; // 引用类型值的复制
obj2.name = 'Bob';
console.log(obj1.name); // 输出: 'Bob'
console.log(obj2.name); // 输出: 'Bob'

因此,在JavaScript中,了解基本类型值和引用类型值的区别对于编写高效的代码和避免意外行为非常重要。

浅克隆和深克隆

浅克隆

浅克隆是指创建一个新对象,该对象具有与原始对象相同的属性和值,但是对于对象中的嵌套对象(引用类型值),只复制了它们的引用而不是深层复制它们的内容。在JavaScript中,可以使用几种方法来进行浅克隆。

  1. 使用对象展开运算符(Spread Operator)
const originalObj = { a: 1, b: { c: 2 } };
const clonedObj = { ...originalObj };clonedObj.b.c = 3; // 修改克隆后的对象的嵌套对象属性
console.log(originalObj.b.c); // 输出: 3,因为只是引用的复制
  1. 使用Object.assign()方法
//OObject.assign(target, ...sources):如果目标对象与源对象具有相同的键(属性名),则目标对象中的属性将被源对象中的属性覆盖,后面的源对象的属性将类似地覆盖前面的源对象的同名属性。
const originalObj = { a: 1, b: { c: 2 } };
const clonedObj = Object.assign({}, originalObj);clonedObj.b.c = 3; // 修改克隆后的对象的嵌套对象属性
console.log(originalObj.b.c); // 输出: 3,因为只是引用的复制
  1. 使用Array.prototype.slice()方法(仅适用于数组)
const originalArr = [1, 2, { a: 3 }];
const clonedArr = originalArr.slice();clonedArr[2].a = 4; // 修改克隆后的数组的嵌套对象属性
console.log(originalArr[2].a); // 输出: 4,因为只是引用的复制

这些方法都可以实现浅克隆,但需要注意的是,嵌套对象的修改会影响到原始对象和克隆对象,因为它们共享相同的引用。如果需要深层复制对象,即使嵌套对象也被复制而不是共享引用,需要使用深层克隆技术。

深克隆

深克隆是指创建一个新对象,该对象具有与原始对象相同的属性和值,包括原始对象中的所有嵌套对象,而不是共享引用。在JavaScript中,实现深克隆可以使用递归或其他方法来遍历对象的所有属性并进行复制。

以下是一种实现深克隆的简单方法:
方法一:

// 深拷贝
const obj3 = { a: 0, b: { c: 0 } };
const obj4 = JSON.parse(JSON.stringify(obj3));
//JSON.parse()
//解析 JSON 字符串并返回对应的值,可以额外传入一个转换函数,用来将生成的值和其属性,在返回之前进行某些修改。
//JSON.stringify()
//返回与指定值对应的 JSON 字符串,可以通过额外的参数,控制仅包含某些属性,或者以自定义方法来替换某些属性值。
obj3.a = 4;
obj3.b.c = 4;
console.log(obj4); // { a: 0, b: { c: 0 } }

方法二:

function deepClone(obj) {// 检查是否为对象,如果不是,则直接返回if (obj === null || typeof obj !== 'object') {return obj;}// 创建一个新的对象或数组来存储克隆后的数据const clone = Array.isArray(obj) ? [] : {};// 遍历原始对象的属性,并递归调用deepClone函数进行深层复制for (let key in obj) {if (Object.prototype.hasOwnProperty.call(obj, key)) {clone[key] = deepClone(obj[key]);}}return clone;
}

使用示例:

const originalObj = {a: 1,b: {c: 2,d: [3, 4]}
};const clonedObj = deepClone(originalObj);clonedObj.b.c = 5;
clonedObj.b.d.push(6);console.log(originalObj); // 输出: { a: 1, b: { c: 2, d: [3, 4] } }
console.log(clonedObj); // 输出: { a: 1, b: { c: 5, d: [3, 4, 6] } }

这个实现通过递归地遍历对象的所有属性和嵌套对象,并创建它们的副本,从而实现了深度复制。需要注意的是,这种方法对于循环引用的情况可能会导致栈溢出,因此在处理可能包含循环引用的对象时需要添加相应的处理逻辑。

全篇重要知识点

  1. 数组是什么?应该如何定义?
  2. 如何检测数组类型?
  3. 数组有哪些常用方法?
  4. 数组的遍历相关算法、去重和随机样本、冒泡排序
  5. 基本类型值和引用类型的区别
  6. 实现浅克隆和深克隆

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

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

相关文章

enable_shared_from_this使用笔记

解决了&#xff1a; 不能通过原指针增加引用次数的问题 &#xff0c;通过weak_ptr实现。 class MyCar:public std::enable_shared_from_this<MyCar> { public:~MyCar() { std::cout << "free ~Mycar()" << std::endl; } };int main() { MyCar* _…

centos7下fastdfs分布式部署

需要先在159及120服务器上安装fastdfs服务 可参考&#xff1a;centos7部署FastDFS服务_centos fastdfs 增加到服务中-CSDN博客 1、整体架构&#xff0c;使用3个服务器节点&#xff0c;其中两台为跟踪器节点及存储节点&#xff0c;一台服务器搭建nginx做统一入口进行负载均衡 …

K8S安装并搭建集群

1. 先给每台机器安装docker环境 卸载旧的docker yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engine 配置docker的yum库 yum install -y yum-utilsyum-config-manager --a…

JavaEE之线程(3)_线程的开始、中断、等待、休眠线程、线程的状态

前言 在本栏的上一节&#xff08;https://blog.csdn.net/2301_80653026/article/details/138500558&#xff09;&#xff0c;我们重点讲解了五种不同的创建线程的方式&#xff0c;我们还介绍了Tread类的常见构造方法和常见属性&#xff0c;在这一节中我们将会继续介绍Tread类。…

简单的Python HTML 输出

1、问题背景 一名初学者在尝试将 Python 脚本输出到网页上时遇到了一些问题。他当前使用 Python 和 HTML 进行开发&#xff0c;并且遇到了以下问题&#xff1a; 担心自己的代码过于复杂&#xff0c;尤其是 WebOutput() 函数。希望通过 JavaScript 使用 HTML 模板文件更新数据。…

【PG数据库】PostgreSQL 日志归档详细操作流程

1.1 日志归档的目的 pg数据库日志归档是将PostgreSQL数据库的日志文件进行归档的过程。 归档的主要目的是为了保留历史数据&#xff0c;确保数据的一致性和完整性&#xff0c;同时为数据恢复提供必要的支持。 pg数据库日志归档的目的包括&#xff1a; 1.数据恢复&#xff1…

Tomcat中服务启动失败,如何查看启动失败日志?

1. 查看 localhost.log 这个日志文件通常包含有关特定 web 应用的详细错误信息。运行以下命令查看 localhost.log 中的错误&#xff1a; sudo tail -n 100 /opt/tomcat/latest/logs/localhost.YYYY-MM-DD.log请替换 YYYY-MM-DD 为当前日期&#xff0c;或选择最近的日志文件日…

【打工日常】云原生之搭建一款轻量级的开源Markdown笔记工具

一、flatnotes介绍 1.flatnotes简介 一个自托管的&#xff0c;无数据库的笔记网络应用程序&#xff0c;利用平面文件夹的markdown文件进行存储。 2.项目特点 A.干净简单的用户界面B.响应式移动端界面C.原生/所见即所得Markdown编辑模式D.高级搜索功能E.笔记“标签”功能F.…

Java入门基础学习笔记12——变量详解

变量详解&#xff1a; 变量里的数据在计算机中的存储原理。 二进制&#xff1a; 只有0和1&#xff0c; 按照逢2进1的方式表示数据。 十进制转二进制的算法&#xff1a; 除二取余法。 6是110 13是1101 计算机中表示数据的最小单元&#xff1a;一个字节&#xff08;byte&…

【mysql篇】执行delete删除大量数据后,磁盘未清空,为什么?

目录 迁移脚本删除数据以及备份数据 解决方法OPTIMIZE TABLE二进制日志按月生成数据 最近某个项目虽说用户量不大&#xff0c;但是&#xff0c;单表的数据量越来越大&#xff0c;mysql一般单表超过千万级别后&#xff0c;性能直线下降&#xff0c;所以利用shardingphere按月做了…

用python进行接口测试(详细教程)

前言 其实我觉得接口测试很简单&#xff0c;比一般的功能测试还简单&#xff0c;现在找工作好多公司都要求有接口测试经验&#xff0c;也有好多人问我什么是接口测试&#xff0c;本着不懂也要装懂的态度&#xff0c;我会说&#xff1a;所谓接口测试就是通过测试不同情况下的入…

mac内存不足怎么清理?有哪些免费的软件工具?

当你的mac电脑使用一段时间之后&#xff0c;你可能就会发现&#xff0c;原本非常流畅的运行开始出现卡顿的现象&#xff0c;此时正是mac内存不足的外在表现。可mac内存不足怎么清理呢&#xff0c;别急&#xff0c;清理内存的方式方法有很多&#xff0c;小编将结合实际情况给大家…

免费实用在线AI工具集合

免费在线工具 https://orcc.online/ 在线录屏 https://orcc.online/recorder pdf在线免费转word文档 https://orcc.online/pdf 时间戳转换 https://orcc.online/timestamp Base64 编码解码 https://orcc.online/base64 URL 编码解码 https://orcc.online/url Hash(MD5/SHA…

网络安全专业岗位详解+自学学习路线图

很多网安专业同学一到毕业就开始迷茫&#xff0c;不知道自己能去做哪些行业&#xff1f;其实网络安全岗位还是蛮多的&#xff0c;下面我会介绍一些网络安全岗位&#xff0c;大家可以根据自身能力与喜好决定放哪个方向发展。 渗透测试/Web安全工程师 主要是模拟黑客攻击&#…

苹果电脑怎么安装crossover 如何在Mac系统中安装CrossOver CrossOver Mac软件安装说明

很多Mac的新用户在使用电脑的过程中&#xff0c;常常会遇到很多应用软件不兼容的情况。加上自己以前一直都是用Windows系统&#xff0c;总觉得Mac系统用得很难上手。 其实&#xff0c;用户可以在Mac上安装CrossOver&#xff0c;它支持用户在Mac上运行Windows软件&#xff0c;例…

Win10鼠标右键新增软件快速打开项

1、cmd 运行 regedit 2、找到该位置的shell文件夹 3、在shell文件夹下创建需要添加的软件名的文件夹&#xff0c;并修改相关信息 4、新建子文件夹command&#xff0c;并修改相关信息 5、效果

十天学会单片机可能吗?单片机入门需要多久?

在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「单片机的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#xff01; 十天学“会”单片机&#xf…

亚马逊广告怎么优化?11条口诀请谨记

对于亚马逊卖家来说&#xff0c;想要销量好&#xff0c;亚马逊广告是不可或缺的&#xff01;那么卖家要如何优化亚马逊广告才可以获得更好的效果呢&#xff1f;今天给大家分享11条亚马逊广告优化口诀&#xff0c;赶紧收藏学起来吧&#xff01; 亚马逊广告优化口诀分享 1、曝光高…

党务政务服务热线|基于SSM的党务政务服务热线平台(源码+数据库+文档)

目录 基于SprinBootvue的党务政务服务热线平台 一、前言 二、系统设计 三、系统功能设计 1系统功能模块 2后台功能模块 5.2.1管理员功能模块 5.2.2部门功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; …

2D-3D 转换中,为什么世界坐标要扩充成四维, 图像坐标要扩充成三维?

总结 在计算机视觉和图形学中&#xff0c;将世界坐标扩充成四维&#xff0c;以及图像坐标扩充成三维&#xff0c;是为了便于运用齐次坐标&#xff08;homogeneous coordinates&#xff09;进行坐标变换。这样的做法简化了投影变换的数学表示和计算&#xff0c;特别是在三维场景…