JavaScript高级程序设计学习笔记(三)
分享一下第五章(引用类型)的笔记,内容比较多,我拆成了两部分,今天这部分是关于Object、Array、Date和RegExp类型的。
以下的笔记是书上一些我以前学习的时候,没有太重视的js基础知识,也有一些面试知识的拓展,通过博客回顾并加深理解。
文章目录
- 第五章(上)
- 引用类型
- Object类型
- 实例化方法
- 访问对象属性
- Array类型
- 创建方式
- 检测数组
- 转换方法
- 栈方法
- 队列方法
- 数组的重排序方法
- 操作方法
- concat()方法
- slice()方法
- splice()方法
- 关于concat和slice的浅拷贝
- 关于concat和slice浅拷贝的总结
- 位置方法
- 例题解析
- 迭代方法
- 归并方法
- Date类型
- 构造方法
- RegExp类型
- 语法
- 实例属性
- 实例方法
- exec()方法(用于捕获组)
- test()方法
- RegExp的构造函数属性(仅作了解)
- 总结
第五章(上)
引用类型
Object类型
实例化方法
new操作符+Object构造函数:
var person=new Object();
person.name="LeoLoge";
person.age=29;
字面量表示法:
var person = { name : "LeoLoge", age : 29,5 : true
};
注意:
1、数值属性名会被自动转换为字符串;
2、最后一个属性后面不要添加逗号(我平时强迫症经常加,在比较早的浏览器版本中会导致错误);
3、字面量表示法可以作为函数参数传递。
function displayInfo(args) {doSomething();
}
displayInfo({ name: "LeoLoge",age: 29
});
访问对象属性
点表示法、方括号表示法
console.log(person.name);
console.log(person["name"]);
注意:
虽然属性名中可以包含非字母非数字,但是包含空格的属性名不能使用点表示法,要用方括号表示法。
console.log(person["first name"]);
Array类型
创建方式
// 第一种 构造函数
var colors = new Array();
var colors = new Array(20);
var colors = new Array("red", "blue", "green");
// 在使用 Array 构造函数时也可以省略 new 操作符。
var colors = Array(3); // 创建一个包含 3 项的数组
var names = Array("Greg"); // 创建一个包含 1 项,即字符串"Greg"的数组 // 第二种 数组字面量表示法
var colors = ["red", "blue", "green"]; // 创建一个包含 3 个字符串的数组
var names = []; // 创建一个空数组
对于字面量表示法,要注意最后一项不要留多余的逗号:
反面教材:
var values = [1,2,]; // 不要这样!这样会创建一个包含 2 或 3 项的数组
var options = [,,,,,]; // 不要这样!这样会创建一个包含 5 或 6 项的数组
可以利用length属性,给数组添加新项:
colors[colors.length]="black";
检测数组
// 第一种:instanceof操作符,它假定只有一个全局执行环境,在存在两个以上不同版本的Array构造函数时会出问题
if (value instanceof Array){doSomething();
}
// 第二种:ES5方法中的Array.isArray()
if (Array.isArray(value)){doSomething();
}
// 第三种:安全的类型检测(本书22.1.1节的高级函数)
function isArray(value){return Object.prototype.toString.call(value)=="[object Array]";
}
转换方法
valueOf()返回的是数组本身,toString()会返回由数组中每个值的字符串形式拼接而成的一个以逗号为分割的字符串。
var colors = ["red", "blue", "green"]; // 创建一个包含 3 个字符串的数组
console.log(colors.toString()); // red,blue,green
console.log(colors.valueOf()); // Array ["red", "blue", "green"]
console.log(colors); // Array ["red", "blue", "green"]
alert(colors.valueOf()) // red,blue,green
因为alert接受的是字符串参数,所以第五行在调用valueOf()之后会再调用toString()方法返回数组的字符串表示。
除此之外,还有一个toLocaleString()方法,如果它有定义,那它会代替toString()被使用于数组的字符串表示。
栈方法
栈是一种LIFO(后进先出)的数据结构,当JavaScript的Array数组作为栈使用的时候,可以使用push()和pop()方法,实现类似栈的行为。
入栈:push()方法可以接收任意数量的参数,把它们逐个添加到数组末尾,并返回修改后数组的长度。
var colors = new Array(); // 创建一个数组
var count = colors.push("red", "green"); // 推入两项
console.log(count); //2
count = colors.push("black"); // 推入另一项
console.log(count); //3
出栈:pop()方法则从数组末尾移除后一项,减少数组的 length 值,然后返回移除的项。请看下面的例子:
var item = colors.pop(); // 取得最后一项
console.log(item); //"black"
console.log(colors.length); //2
队列方法
队列是一种FIFO(先进先出)的数据结构,当JavaScript的Array数组作为队列使用的时候,可以使用push()和shift()方法,实现类似队列的行为。
入列:push()方法和栈方法中的push()是一样的,在数组末端添加项,并返回修改后数组的长度。
出列:shift()方法能够移除数组中的第一个项并返回该项,同时将数组长度减1。请看下面的例子:
var item = colors.shift(); //取得第一项
console.log(item); //"red"
console.log(colors.length); //2
unshift()方法
ECMAScript还为数组提供了一个unshift()方法,用途与shift()方法相反,作用是在数组前端添加任意个项并返回新数组的长度。
var colors = new Array(); //创建一个数组
var count = colors.unshift("red", "green"); //推入两项
console.log(count); //2
总结:
1、push()和shift()方法能够模拟队列,在数组末端添加项,从数组前端移除项。
2、unshift()和 pop()方法,则可以从相反的方向来模拟队列,即在数组的前端添加项,从数组末端移除项。
数组的重排序方法
数组中已经存在两个可以直接用来重排序的方法:reverse()和 sort()。
值得注意的是,这两个方法会改变原来的数组,而不会创建新的数组。
reverse()方法
reverse()方法会直接反转数组元素的顺序,使用见下例:
var values = [1, 2, 3, 4, 5];
values.reverse();
console.log(values); //Array [5,4,3,2,1]
sort()方法
在默认情况下,sort()方法按升序排列数组项——即小的值位于前面,大的值排在后面。 为了实现排序,sort()方法会调用每个数组项的 toString() 转型方法,然后比较得到的字符串,以确定如何排序。也就是说,即使数组中的每一项都是数值,sort()方法比较的也是字符串,如下所示。
var values = [0, 1, 5, 10, 15];
values.sort();
console.log(values); //Array [0,1,10,15,5]
这样看来,sort()方法的默认排序方式就显得很诡异了,如果我要排数字怎么办?因此,sort()方法可以接收一个比较函数作为参数,以便我们指定哪个值位于哪个值前面。
而比较函数接收两个参数,如果第一个参数想位于第二个参数之前,那就返回负数(比如说升序,那就是当第一个参数小于第二个参数时,返回负数),参数相等返回0,如果第一个参数想位于第二个参数之后,那就返回正数。
我其实不怎么能记住上面的规律,所以我理解的这个比较函数的方式是:返回1的情况代表要执行交换。
所以对于升序来说,当第一个参数大于第二个参数的时候就要执行交换,所以返回1,由此推出升序时比较函数的形式(见下方);降序同理,当第一个函数小于第二个参数的时候返回1。
比如说我们想要数字升序,可以这样写:
function compare(value1, value2) {if (value1 < value2) { //升序,返回负数return -1;} else if (value1 > value2) { return 1; } else {return 0; }
}
var values = [0, 5, 1, 10, 15];
values.sort(compare);
console.log(values); //Array [0,1,5,10,15]
这样就可以按照我们想要的规律去排序数组了,但其实比较函数的形式还可以再精简一些,适用于数组元素(下面的value)是数值类型,或者其valueOf()方法会返回数值类型的对象类型:
// 升序
function compare(value1, value2) {return value1-value2;
}
// 降序
function compare(value1, value2) {return value2-value1;
}
// 比较函数返回的必须是数值,才能影响排序结果!
操作方法
数组的操作方法,书上讲到的有concat()、slice()还有splice()。
(之前在concat()和slice()上踩过浅拷贝的坑,一会儿会拓展一下)
concat()方法
拼接一个或多个数组,并返回一个新构建的数组,如下:
var colors = ["red", "green", "blue"];
var colors2 = colors.concat("yellow", ["black", "brown"]); alert(colors); //red,green,blue 不影响原数组
alert(colors2); //red,green,blue,yellow,black,brown
slice()方法
基于当前数组的一项或多项来创建新数组,接收两个参数,第一个是起始位置,第二个是可选的结束位置,如下:
var colors = ["red", "green", "blue", "yellow", "purple"];
var colors2 = colors.slice(1);
var colors3 = colors.slice(1,4);
alert(colors); //red,green,blue,yellow,purple 不影响原数组
alert(colors2); //green,blue,yellow,purple
alert(colors3); //green,blue,yellow
splice()方法
splice()方法非常强大,主要用途是向数组的中部插入项,方式有以下三种:
1、删除:
删除任意数量的项,提供两个参数,一个是第一项的位置,另一个是删除的项数,返回的是被删除的部分组成的数组。
// 删除第一项red
var colors = ["red", "green", "blue"];
var removed = colors.splice(0,1); // 删除第一项
alert(colors); // green,blue
alert(removed); // red,返回的数组中只包含一项
2、插入:
向指定位置插入任意数量的项,提供三个参数,起始位置、0(要删除的项数)、要插入的项(传多个参数),返回值也是被删除的部分组成的数组,因为是插入,所以返回的是空数组。
// 插入yellow和orange
var colors = ["green", "blue"];
removed = colors.splice(1, 0, "yellow", "orange"); // 从位置 1 开始插入两项
alert(colors); // green,yellow,orange,blue
alert(removed); // 返回的是一个空数组
3、替换:
其实就是基于插入,在第二个参数上指定删除的项数,来达到替换任意数量的项。
// 把yellow换成red和purple
var colors = ["green", "yellow", "blue"];
removed = colors.splice(1, 1, "red", "purple"); // 插入两项,删除一项
alert(colors); // green,red,purple,blue
alert(removed); // yellow,返回的数组中只包含一项
关于concat和slice的浅拷贝
我们经常遇到拷贝数组的情景,比如说:
var arr1 = ["red","yellow","black"];
// 要注意这里数组的元素,是基本数据类型(String)
var arr2 = arr1;
arr2[1] = "green";
console.log("数组的原始值:" + arr1);//数组的原始值:red,green,black
console.log("数组的新值:" + arr2);//数组的新值:red,green,black
上面这种拷贝方式会拷贝数组的引用,所以实质上没有真正创建副本。
想要复制一个数组副本,我们可以用concat和slice方法:
var arr1 = ["1","2","3"];
var arr2 = arr1.slice(0);
arr2[1] = "9";
console.log(arr1.toString());//1,2,3
console.log(arr2.toString());//9,2,3var arr3 = arr1.concat();
arr3[1] = "9";
console.log(arr1.toString());//1,2,3
console.log(arr3.toString());//9,2,3
这样算是拷贝成功了,但刚刚也说了,数组元素是基本类型的时候才适用,所以这两种方法其实是浅拷贝(跟第二篇笔记讲到的Object.assign()方法一样),当数组元素存在对象,即数据存在更多的层级的时候,就会出大问题:
// 第一个例子
const a1 = [{ a: 1 }]
const b1 = [{ b: 1 }]
const c1 = [...a1, ...b1]//ES6的扩展运算符,浅拷贝
const c2 = a1.concat(b1)//concat,浅拷贝c1[0].a = 3
c2[1].b = 4 console.log(a1[0].a) // 3 原数组a1里的第一个对象的a变成了3
console.log(b1[0].b) // 4 原数组b1里的第一个对象的b变成了4// 另一个例子,二维数组的slicevar a1=[["1","2","3"],"2","3"];
var a2=a1.slice(0);
a1[0][0]=0; //改变a1第一个元素中的第一个元素为0
a1[1]=5; //把第二个元素改成5
console.log(a2[0][0]); //0 影响到了a2
console.log(a2[1]); //2 第一层的非引用类型没受影响
第一个例子是因为数组成员是对象,对象它是引用类型,通过对外层数组的浅拷贝,你是没办法新建内部引用类型值的副本的,只能拷贝到对对象的引用。
显然,第二个例子也是这么个原因,a1数组的第一个元素是个数组,而数组(Array)是引用类型,自然也不会被拷贝,你拷贝到的只是对它的引用。
关于concat和slice浅拷贝的总结
slice和concat这两个方法,仅适用于对不包含引用对象的一维数组的拷贝,它们都属于浅拷贝。
想要深拷贝包含引用对象的数组或者是多维数组,还是得用JSON.parse(JSON.stringify(object))。
深浅拷贝的知识可以见我的第二篇笔记:JavaScript高级程序设计学习笔记(二)
位置方法
indexOf()和lastIndexOf()这两个方法很简单,是用来找索引下标的,一个向后查,一个向前查,除了要查找的参数外,还可以再给定查找起点作为第一个参数。
需要注意的是,这两个方法使用全等操作符(===)去比较参数和数组中的每一项,查找项要严格相等。
var person = { name: "Nicholas" };
var people = [{ name: "Nicholas" }]; var morePeople = [person]; alert(people.indexOf(person)); //-1
alert(morePeople.indexOf(person)); //0
如果和我一样是基础不太扎实的读者,在看完上面的例子之后,你大概会有疑问,为啥people里找不到person,而morePeople却可以找到person?在书上没有解释(作者以为你懂了,但实际上你没有),作为一个决心要把书吃透的人,我马虎不得,不能放过这个细节。
例题解析
第一行代码,person是对象{ name: “Nicholas”}的引用A,是一个对象指针。
第二行代码,people是一个包含对象{ name: “Nicholas”}的另一个引用B的数组。
第三行代码,morePeople 是一个包含对象{ name: “Nicholas”}的引用A的数组。
第四行代码,people中只有引用B,没有引用A(person),所以返回-1。
第五行代码,morePeople中有引用A(person),索引是0,返回0。
迭代方法
ES5定义了5个迭代方法,每个方法都接收两个参数:要在每一项上运行的函数和 (可选的)运行该函数的作用域对象——影响 this 的值。传入这些方法中的函数会接收三个参数:数 组项的值、该项在数组中的位置和数组对象本身。
书上这一段定义给我看懵了,概括一下,以foreach为例子,形式如下:
Array.forEach(function(value , index , array){//value为遍历的当前元素,index为当前索引,array为正在操作的数组//do something
},thisArg) //thisArg为执行回调时的this值
1、every():对数组中的每一项运行给定函数,如果该函数对每一项都返回true,则返回 true。
var numbers = [1,2,3,4,5,4,3,2,1];
var everyResult = numbers.every(function(item, index, array){return (item > 2);});
alert(everyResult); //false 有不满足条件的项存在
2、filter():对数组中的每一项运行给定函数,返回该函数会返回 true 的项组成的数组。
var numbers = [1,2,3,4,5,4,3,2,1];
var filterResult = numbers.filter(function(item, index, array){return (item > 2);}); alert(filterResult); //[3,4,5,4,3] 返回满足条件的项组成的数组
3、forEach():对数组中的每一项运行给定函数。这个方法没有返回值。
var numbers = [1,2,3,4,5,4,3,2,1];
numbers.forEach(function(item, index, array){//执行某些操作
});
foreach()方法简洁易用,效率和for循环相同,且不用关心集合下标的问题,减少了出错的可能。
但它也有缺点,比如说:
①不能同时遍历多个数组,在遍历的时候无法修改和删除数据;
②不能使用break,continue语句跳出循环,或者使用return从函数体返回,对于空数组不会执行回调函数。
4、map():对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组。
var numbers = [1,2,3,4,5,4,3,2,1];
var mapResult = numbers.map(function(item, index, array){return item * 2;});
alert(mapResult); //[2,4,6,8,10,8,6,4,2] 全部乘2
5、some():对数组中的每一项运行给定函数,如果该函数对任一项返回 true,则返回 true。
var numbers = [1,2,3,4,5,4,3,2,1];
var someResult = numbers.some(function(item, index, array){return (item > 2);});
alert(someResult); //true 只要有一项存在就返回true
归并方法
ES5的两个归并数组的方法:reduce()和 reduceRight()。这两个方法都会迭代数组的所有项,然后构建一个终返回的值。其中,reduce()方法从数组的第一项开始,向后遍历。而reduceRight()则从数组的最后一项开始,向前遍历。
这两个方法都接收两个参数:一个在每一项上调用的函数和作为归并基础的初始值(可选的),这个初始值是指传入函数的初始值,当函数需要传入额外参数的时候可以使用。
传给 reduce()和 reduceRight() 的函数接收 4 个参数:前一个值、当前值、项的索引和数组对象。这个函数返回的任何值都会作为第一个参数自动传给下一项。第一次迭代发生在数组的第二项上,因此第一个参数是数组的第一项,第二个参数就是数组的第二项。
1、reduce()
var values = [15.5, 2.3, 1.1, 4.7];
var sum = values.reduce(function(prev, cur, index, array){return prev+ Math.round(cur);//求数组元素四舍五入后的和(除了首项)
});
alert(sum); //23.5
2、reduceRight()
与reduce()方法同理,只是逆序遍历。
var values = [15.5, 2.3, 1.1, 4.7];
var sum = values.reduceRight(function(prev, cur, index, array){return prev+ Math.round(cur);//求数组元素四舍五入后的和(除了末项)
});
alert(sum); //23.7
Date类型
这个类型是根据早期Java中的java.util.Date类基础上构建的,。为此,Date 类型使用自 UTC(Coordinated Universal Time,国际协调时间)1970年1月1日午夜(零时)开始经过的毫秒数来保存日期。
(老实说Date类型我用的比较少)
构造方法
var now=new Date(); //不传入参数,默认获取当前时间
//第一种转毫秒数的方法:Date.parse()
var someDate=new Date(Date.parse("May 25,2019"));
//注意,如果传入的字符串不能表示日期,会返回NaN
var otherDate=new Date("May 25,2019");
//如果传入日期字符串,会在后台调用Date.parse()方法转换为毫秒数//第二种转毫秒数的方法:Date.UTC()
var someDate=new Date(Date.UTC(2000,0));
//至少要传前两个参数(年和月)
//月份为0代表一月,为1代表二月,以此类推
var otherDate=new Date(Date.UTC(2008,4,5,18,55,55));//返回当前时间的Date.now()方法,返回表示调用这个方法时的日期和时间的毫秒数
var start = Date.now();
doSomething();
var stop = Date.now(),result = stop – start;//与Date.now()等价的方法(+操作符)
var start = +new Date();
var stop = +new Date();
RegExp类型
语法
var expression=/pattern/flags;
其中flags支持以下三种:
g:表示全局(global)模式,即模式将被应用于所有字符串,而非在发现第一个匹配项时立即 停止;
i:表示不区分大小写(case-insensitive)模式,即在确定匹配项时忽略模式与字符串的大小写;
m:表示多行(multiline)模式,即在到达一行文本末尾时还会继续查找下一行中是否存在与模 式匹配的项。
创建正则表达式也分了两种方式,一种是字面量形式,另一种就是RegExp构造函数。
/* 匹配第一个"bat"或"cat",不区分大小写 */
var pattern1 = /[bc]at/i; /* 与 pattern1 相同,只不过是使用构造函数创建的 */
var pattern2 = new RegExp("[bc]at", "i");
实例属性
1、global:布尔值,表示是否设置了 g 标志。
2、ignoreCase:布尔值,表示是否设置了 i 标志。
3、lastIndex:整数,表示开始搜索下一个匹配项的字符位置,从 0算起。
4、multiline:布尔值,表示是否设置了 m 标志。
5、source:正则表达式的字符串表示,按照字面量形式而非传入构造函数中的字符串模式返回。
实例方法
exec()方法(用于捕获组)
exec()方法接受一个参数,即 要应用模式的字符串,然后返回包含第一个匹配项信息的数组;或者在没有匹配项的情况下返回 null。
返回的数组虽然是 Array 的实例,但包含两个额外的属性:index 和 input。其中,index 表示匹配 项在字符串中的位置,而 input 表示应用正则表达式的字符串。在数组中,第一项是与整个模式匹配的字符串,其他项是与模式中的捕获组匹配的字符串(如果模式中没有捕获组,则该数组只包含一项)。
对于模式中有捕获组的正则表达式,返回数组的形式可以看下面的例子。
var text = "mom and dad and baby";
var pattern = /mom( and dad( and baby)?)?/gi; var matches = pattern.exec(text);
alert(matches.index); // 0
alert(matches.input); // "mom and dad and baby"
alert(matches[0]); // "mom and dad and baby"
alert(matches[1]); // " and dad and baby"
alert(matches[2]); // " and baby"
test()方法
test()方法接受一个字符串参数。在模式与该参数匹配的情况下返回 true;否则,返回 false。
在只想知道目标字符串与某个模式是否匹配,但不需要知道其文本内容的情况下,使用这个方法非常方便。因此,test()方法经常被用在 if 语句中。
var text = "000-00-0000";
var pattern = /\d{3}-\d{2}-\d{4}/;
if (pattern.test(text)){alert("The pattern was matched.");
}
这种用法经常出现在验证用户输入的情况下,因为我们只想知道输入是不是有效,至于它为 什么无效就无关紧要了。
RegExp的构造函数属性(仅作了解)
RegExp 构造函数包含一些属性(这些属性在其他语言中被看成是静态属性)。这些属性适用于作用域中的所有正则表达式,并且基于所执行的近一次正则表达式操作而变化。
详细了解RegExp的属性可以通过阅读以下文档:
RegExp - JavaScript | MDN
总结
这里面最需要重点了解的应该就是Array和RegExp类型了,一段学习下来我才发现,之所以做题的时候数据结构用得不熟练,主要还是因为对引用类型的内置属性和方法的不熟悉,像反向队列的实现我也是才了解到。
下次会把函数类型和基本包装类型回顾一下。
本文内容如果有理解有误的地方,还请大家指正!
如果对你产生了帮助,请点个赞给我吧!感谢观看!
JavaScript高级程序设计学习笔记(三)相关推荐
- javascript高级程序设计学习笔记
javascript高级程序设计,当枕头书已经好久了~zz 现在觉得自己在js的开发上遇到了一些瓶颈,归根究底还是基础太薄弱,所以重新刷一遍js高程希望有更新的认识. 一.javascript简介 ...
- javascript高级程序设计 学习笔记 第五章 上
第五章 引用类型的值(对象)是引用类型的一个实例.在 ECMAScript 中,引用类型是一种数据结构, 用于将数据和功能组织在一起.它也常被称为类,但这种称呼并不妥当.尽管 ECMAScri ...
- JavaScript高级程序设计学习笔记第二十章--JSON
1.JSON:JavaScript Object Notation, JavaScript 对象表示法. 2.最重要的是要理解它是一种数据格式,不是一种编程语言.虽然具有相同的语法形式,但 JSON ...
- JavaScript高级程序设计学习笔记----初识JavaScript
一.JavaScript概述 1.JavaScript 介绍: 简称JS,是一种浏览器解释型语言,嵌套在HTML文件中交给浏览器解释执行.主要用来实现网页的动态效果,用户交互及前后端的数据传输等. 2 ...
- JavaScript高级程序设计--学习笔记(第六章)
文章目录 第六章 面向对象的程序设计 1. 理解对象 1.1 属性类型 1.2 定义多个属性 1.3 读取属性的特性 2. 创建对象 2.1 工厂模式 2.2 构造函数模式 2.3 原型模式 2.4 ...
- JavaScript高级程序设计学习笔记--引用类型
Object类型 对象字面量表示法: var person={ name:"Nicholas", age:29, 5:true }; 这人例子会创建一个对象,包含三个属性:name ...
- JavaScript高级程序设计学习笔记二(在HTML中使用JavaScript)
在 HTML 中使用 JavaScript 在html中使用JavaScript脚本有两种方式一种是嵌入在HTML中的脚本,另一种是引入外部的脚本.两种方式都离不开<script>元素. ...
- JavaScript高级程序设计学习笔记6:正则表达式
一.正则表达式通过RegExp类实现,RegExp对象的构造函数可以带一个或两个参数.第一个参数(或只有一个参数)是描述需要进行匹配的模式字符串,如果还有第二个参数,这个参数则指定了额外的处理指令. ...
- JavaScript高级程序设计---学习笔记(四)
1.全局变量不能通过delete操作符删除,而直接在window对象上定义的属性可以. var age = 29;window.color = "red";delete age;/ ...
最新文章
- 嵌入式系统低功耗管理(备忘)
- c# 5.0入门经典笔记
- jdbc连接mysql传参_将参数传递给JDBC PreparedStatement
- 洛谷 P1417 烹调方案 (01背包拓展)
- Oracle 直方图理论
- windows.open()参数列表
- java中使用nextLine(); 没有输入就自动跳过的问题?
- org.jbpm.configuration.ConfigurationException: name 'default.jbpm.context'
- 浅谈php之设计模式基础
- 【docker】docker持续集成CI/持续部署CD
- 基于Matlab数字图像处理微表情情绪识别系统
- PhotoShop CS5制作残旧的印章效果
- WPS简历模板的图标怎么修改_指导|让疫情之下的应届生,求职简历脱颖而出
- 循环结构——分数化简
- java写颜色识别_Java+Opencv 颜色识别
- LCD显示屏的器件选择和驱动电路设计
- pq分解法matlab程序,基于MATLAB软件的PQ分解法潮流计算
- java压缩文件,在线下载文件并压缩
- PaaS简介及国内PaaS平台
- php frameset不显示,如何解决php加载frameset页面时显示空白问题
热门文章
- springboot整合netty实现tcp通信
- 【论文阅读】Automatic Detection of Various Malicious Traffic Using Side Channel Features on TCP Packets
- php爬虫爬取校园新闻,python爬虫获取校园网新闻
- 用一个月面试了 大厂,中厂,小厂的总结|2021 年中总结
- 小巧灵便的桌面工具带有便签、闹钟、任务管理功能
- 转载:毕业半年在富士康的经历
- GEA 3.3 捕捉及处理错误
- ACM--South Pacific 2012
- 珠宝erp是否能带回珠宝行业的“黄金时代”?
- 2021 typescript史上最强学习入门文章(4w字)