基本类型
概述
- string、number、boolean、symbol有构造函数
- undefined、null无构造函数
- typeof null=="object",这是历史遗留问题;null仍是基本数据类型
构造函数
- new Number(任意类型):任意类型转成十进制数
- Number(任意类型):任意类型转成十进制数
- new String(任意类型):任意类型转成string类型
- String(任意类型):任意类型转成string类型
- new Boolean(true)
- Boolean(false)
- Symbol("symbol")
调用原型方法
- 调用方式1:("123").split("")
- 调用方式2:let str="123"; str.split("")
Object类型
构造函数
new Object({}) <=> Object({}) <=> {}
函数方法
- Symbol属性不可枚举
- create、freeze、seal
- assign(target,...args):把...args的可枚举属性赋值到target对象
- getPrototypeOf、setPrototypeOf
- defineProperties、defineProperty
- keys:所有可枚举属性数组
- values:所有可枚举属性的值数组
- entries:所有可枚举属性的键值对数组
- getOwnpropertySymbols:所有Symbol属性数组
原型方法
- hasOwnProperty("xxx"):检查是否包括可枚举属性xxx
- isPrototypeOf、propertyIsEnumerable
- toString、valueOf、toLocaleString
使用
- Object.seal(obj):obj不能添加和删除属性,但是可以修改属性值
- Object.seal(arr):arrj不能添加和删除元素,但是可以修改元素值
- Object.preventExtensions(obj):obj不能添加属性,能删除属性
Function类型
构造函数
- const 函数名=new Function(参数1,参数2,……,函数体)
- const 函数名=Function(参数1,参数2,……,函数体)
- function 函数名(参数1,参数2,……){函数体}
原型对象
- function fun(){}
- fun.__proto__ === Function.prototype
- fun.__proto__.proto === Object.prototype
V8内置对象
Array函数方法
- new Array(3)<=>[,,,]
- Array.isArray(对象):判断对象是数组
Array.from(类数组)<=>[...类数组]<=>Array.prototype.slice.call(类数组)
- Array.from(字符串,fun?)
- Array.from(Set集合,fun?)
- Array.from(Map集合,fun?)
- Arr.from({'0':1,'1',2,length:2},fun?)
Array.prototype.slice.call(类数组)
Array.prototype.map.call(类数组,(element) =>{ return element})
Array.prototype.filter.call(类数组,(element) =>{return true})
手写from
from(类数组){
let arr=new Array(类数组.length)
for(let i=0;i<类数组.length;i++){
arr[i]=类数组[i]
}
return arr
}
手写map
map(类数组,fun){
let arr=new Array(类数组.length)
for(let i=0;i<类数组.length;i++){
arr[i]=fun(类数组[i])
}
return arr
}
Array原型方法
不改变原数组 | concat、join、toString、slice filter、map、reduce、foreach find、includes、indexOf、lastIndexOf |
改变原数组 | push、pop、shift、unshift、splice sort、reverse、fill |
回调函数参数 | value:当前元素的值 index:当前元素的索引 arr:元素所属的数组对象 |
arr[5] obj[5] | 超出元素范围的元素==undefined arr[5]<=>arr["5"] obj={ 3:"Tom", 3自动转成字符串"3" 2:"Jack", 2自动转成字符串"2", 5:"good" 5自动转成字符串"5", } obj[5]<=>obj["5"] |
arr.splice( index, 删除起始索引 num, 删除元素数量 add1, 添加的元素1 add2 添加的元素2 ):删除元素组成的数组 | index处删除,index右面的元素集体左移 index处添加,iindex以及右面的元素集体右移 |
arr.join(str) | 合成的字符串=(arr.length)个数组元素+(arr.length-1)个str |
arr.fill(数据) | 数据是基本类型:所有数组元素等于相同的值 数据是对象:所有数组元素指向同一对象 核心用法:new Array(n).fill(0),填充空item |
arr.toString() arr=[1,2] | arr.toString()<=>arr.join(',')<=>1,2 |
arr.valueOf() arr=[1,2] | arr.valueOf()==arr<=>[1,2] |
arr.every(item=>{}) | 所有回调函数返回true,结果返回true 有一个不返回true,结果返回false |
arr.some(item=>{}) | 有回调函数返回true,结果返回true 全都没返回true,结果返回false |
arr.includes(item) | arr数组有item,结果返回true arr数组无item,结果返回false |
arr.find(item=>{}) | 有回调函数返回true,结果返回本次回调传入的item 全都的回调都没返回true,结果返回undefined |
arr.sort((el1,el2)=>{return num=el1-el2})
- 数组中的位置:el1在el2的右边
- num>=0,el1和el2的位置不变
- num<0,el1和el2交换位置
String原型方法
不改变原字符串 | contact、repeat、slice、from subString、trim、split toLowerCase、toUpperCase match、matchAll replace、replaceAll search |
查找||判断 | charAt、indexOf、includes startsWith、endsWith |
查找||判断参数 | 参数1:查找||判断的数据 参数2:查找||判断的起始索引 |
str.substring(beginIndex,endIndex) str.slice(beginIndex,endIndex) | 前闭后开 |
str.indexOf(字符,beginIndex) | 从左向右检索[beginIndex,str.length-1] ======> |
str.lastIndexOf(字符,beginIndex) | 从右向左检索[0,beginIndex] <====== |
str.split(分隔符字符串) | str中有n个分割符字符串,会产生长度为n+1的数组 |
str.charAt(index) | 获取指定位置的字符 超出str范围,会返回空字符串 |
str.charCodeAt(index) | 获取指定位置字符的ascii码 超出str范围,返回NaN |
strA.search(regex) | 只有非全局模式 匹配成功,返回首个满足条件的子串的索引 匹配失败,返回-1 |
strA.match(regex) | 非全局模式 匹配成功,返回首个满足条件的子串详细信息 result[0]=匹配结果 result.index=匹配结果起始索引 result.input=参与的匹配字符 result.groups=匹配结果分组 匹配失败,返回null |
全局模式 匹配成功,返回全部满足条件的子串 匹配失败,返回null | |
strA.replace(regex,strb) | 非全局模式 返回替换后的strA,首个满足条件的子串stra被替换为strb |
全局模式 返回替换后的strA,所有满足条件的子串stra被替换为strb | |
strA.matchAll(regex) | 只有全局模式 匹配成功,返回全部满足条件的子串详细信息 |
strA.replaceAll( regex||subStr, strb||(result,index,input,groups) ) | 只有全局模式 返回替换后的strA,所有满足条件的子串stra被替换为strb |
转义字符
- \n:换行符
- \t:制表符
- \r:回车符
- \":双引号
- \':单引号
- \\:反斜杠
- \b:退格符
- \f:换页符
- \v:垂直制表符
Number函数方法
- Number.isInteger(num):判断num是整数
- Number.isNaN(数据):判断是NaN
- NaN==NaN:结果是false
- "_"分隔数字:100100100===100_100_100
Number原型方法
- num.toString(n进制):十进制数转成n进制字符串
- num.toPrecision(n):保留n位数
- num.toFixed(n):保留n位小数
- num.toExponential(n):转换成科学计数法格式的字符串,并保留n为小数
- num.toLocaleString():转换成特定格式的字符串;默认转换成含有逗号的字符串
Symbol对象
- 作用:创建唯一的、不可改变的符号
Symbol扩展普通对象
const o={}
用于 for of迭代
o.[Symbol.iterator]=function* (){
for(const key of Object.keys(this)){
yield [key,this[key]]
}
}
用于 o.toString() => "[object o]"
o.[Symbol.toStringTag]="o"
用于类型强转(o)
o.[Symbol.toPrimitive]=function(type){
type === "number"&&return 10
type === "string"&&return "hello"
return true
}
用于 [] instanceof o
o.[Symbol.hasInstance]
用于字符串的正则
o.[Symbol.match]
o.[Symbol.matchAll]
o.[Symbol.replace]
o.[Symbol.search]
用于字符串的split
o.[Symbol.split]
用于数组的contact
o.[Symbol.isContatSpreadable]
Math对象
- Math.ceil(num):num向上取整
- Math.floor(num):num向下取整
- Math.round(num):四舍五入
- Math.max(a,b,...,c):求最大值
- Math.min(a,b,...,c):求最小值
- Math.abs(num):绝对值
- Math.sqrt(num):num的平方根
- Math.pow(x,y):x的y次幂
- Math.randow():[0,1)之间的随机数
- Math.PI:计算到精度最大,3.14……
JavaScript采用IEEE 754双精度浮点数(64位)
- 64位分成三个部分:符号位、指数位和尾数位
JSON对象
stringify | 数字类型、字符串类型、布尔类型=>字符串类型 null、NaN=>字符串"null" undefined、函数=>undefined 集合=>{} 对象和数组=>JSON格式 |
parse | JSON字符串转成对象 |
Date原型方法
- const date new Date():获取当前时间
- data.getTime():获取时间戳
- date.getFullYear():获取年份
- date.getMonth():获取月份(0是1月,11是12月)
- date.getDate():获取日期
- date.getHours():获取小时
- date.getMinutes():获取分钟
- date.getSeconds():获取秒钟
- date.getDay():获取星期几(0是星期日,1是星期一)
ISO 8601格式
- “YYYY”:年份
- “MM”:月份
- “DD”:日期
- “hh” 12小时制
- “HH” 24小时制
- “mm”:2位数分钟
- “ss”:2位数秒钟
- “sss”:3位数毫秒
- “Z”:时区偏移量表示,例如+08:00表示东八区,-05:00表示西五区
moment库
import moment from 'moment'
//获取当前时间的指定格式:23/08/30 16:20:15
moment().format('YY/MM/DD HH:mm:ss')
//获取指定时间的指定格式
moment("23/08/30 16:20:15").format('YYYY-MM-DD');
const seconds=58.666333
const duration = moment.duration(seconds, 'seconds');
const t=duration.asMilliseconds()
moment.utc(t).format('HH:mm:ss'); //00:00:58
// 获取去年的日期
let lastYearDate = moment().subtract(1, 'year').format('YYYY-MM-DD');
//获取两天前的时间戳
moment().subtract(2,'day').valueOf()
RegExp正则对象
声明 | 构造函数:new RegExp(pattern,modifiers) 简写:/pattern/modifiers |
regex.test(strA) | 匹配strA[regex.lastIndex]后面部分,lastIndex初始值为0 |
非全局模式 匹配成功:返回true,regex.lastIndex=0 匹配失败:返回false,regex.lastIndex=0 | |
全局模式 匹配成功:返回true,regex.lastIndex=stra后一位 匹配失败:返回false,regex.lastIndex=0 | |
regex.exec(strA) | 匹配strA[regex.lastIndex]后面部分,lastIndex初始值为0 |
非全局模式 匹配成功:返回匹配字符串stra详细信息,regex.lastIndex=0 匹配失败:返回null,regex.lastIndex=0 | |
全局模式 匹配成功:返回匹配字符串stra详细信息,regex.lastIndex=stra后一位 匹配失败:返回null,regex.lastIndex=0 |
全局属性方法
- parseInt(str,n进制=10):n进制字符串str转成十进制整数,尽量将字符串解析成整数
- parseFloat(str):字符串str转换成十进制浮点数,尽量将字符串解析成浮点数
Node内置对象
process对象
- process.argv:命令行参数
- process.cwd():运行命令的目录
- process.env:系统环境变量
- process.pid:进程ID
- process.platform:操作系统平台
- process.stdout.write(字符串):标准输出流;console.log底层就是使用stdout.write()
- process.stdin.on('data',(控制台输入数据)=>{}):标准输入流
console.log(process.argv)
//运行指令
PS D:\> node .\test.js -1 -2 -3
['D:\\proSofts\\nodejs\\node.exe','D:\\test.js','-1','-2','-3']
Java的System对象
- 标准输入流:
- BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
- String inputString = br.readLine();
- 标准输出流:System.out.println()
- 命令行目录:System.getProperty("user.dir")
path模块
resolve(path1, path2,...arg ) | 参数中有绝对路径: 保留最后一个绝对路径PathABS,PathABS与后面的相对路径依次连接 参数中没有绝对路径: 绝对路径__dirname,与参数中的相对路径依次连接 |
join(path1, path2,...arg ) | "/xxx"、"xxx"、"./xxx"将转换为"/xxx" "../xxx"会把父级路由删除,如:../aaa/bbb../ccc=>../aaa/ccc |
dirname(path) | 获取文件目录 |
basename(path) | 获取文件名 |
relative(from,to) | from到to的相对路径 |
path.posix | path模块路径分隔符,是反斜杠还是正斜杠,默认根据操作系统而定 Windows系统的路径分隔是反斜杠 使用path.posix,路径分隔符将强制采用正斜杠 |
event模块
注册事件 | myEmitter.on(事件名, callback) myEmitter.addListener(事件名, callback) myEmitter.once(事件名, callback) |
触发事件 | myEmitter.emit(事件名) |
取消注册 | myEmitter.removeListener(事件名, callback) myEmitter.removeAllListeners(事件名) |
const eventNames = myEmitter.eventNames() const listeners = myEmitter.listeners(事件名) |
child_process
- exec:创建新的shell,运行程序;并一次性收到程序输出结果
- execFile:创建系统级子进程,运行程序;并一次性收到程序输出结果
- spawn: 创建系统级子进程,运行程序;以流的方式,实时收到程序输出结果
- fork: 创建nodejs级子进程,运行程序;以流的方式,实时收到程序输出结果
Proxy对象
代理的精髓
在读取变量、设置变量、调用方法之前,执行一段代码
单层代理
- 操作studentMessage不会触发get,set方法
- 操作studentMessageProxy才会触发get,set方法。
let studentMessage={
name:'张三',
age:34
}
let studentMessageProxy=new Proxy(studentMessage,{
get(target,key){
console.log('target',target)
console.log('key',key)
return target[key]
},
set(target,key,newVal){
console.log('target',target)
console.log('key',key)
console.log('newVal',newVal)
target[key]=newVal
}
})
studentMessageProxy.age
studentMessageProxy.age=45
let arr=['小明','男',34]
let arrProxy=new Proxy(arr,{
get(target,key){
console.log('target',target)
console.log('key',key)
return target[key]
},
set(target,key,newVal){
console.log('target',target)
console.log('key',key)
console.log('newVal',newVal)
target[key]=newVal
}
})
arrProxy[0]
arrProxy[0]='李四'
PS C:\Users\Administrator\Desktop\测试\node+浏览器环境测试\proxy的使用> node .\proxy4.js
target { name: '张三', age: 34 }
key age
target { name: '张三', age: 34 }
key age
newVal 45
target [ '小明', '男', 34 ]
key 0
target [ '小明', '男', 34 ]
key 0
newVal 李四
初始化
- let proxyData = new Proxy(data, {get(target, key, receiver) {}})
- Object.setPrototypeOf(obj, proxyData)
target和receiver的指向
- target指向data
- proxyData访问data属性,receiver指向proxyData
- obj访问data属性,receiver指向obj
多层代理
递归实现思路
- 实现对family、friend 的数据劫持
- 实现对 data 的数据劫持
function getProxyData(data){
if(typeof data!=='object'){
return data
}
if(Array.isArray(data)){
for(let i=0;i<data.length;i++){
data[i]=getProxyData(data[i])
}
}
else{
let dataKeys=Object.keys(data)
for(let i=0;i<dataKeys.length;i++){
data[dataKeys[i]]=getProxyData(data[dataKeys[i]])
}
}
data=new Proxy(data,{
get(target,key){
console.log(target)
console.log(key)
return target[key]
},
set(target,key,newVal){
console.log(target)
console.log(key)
console.log(newVal)
target[key]=newVal
}
})
return data
}
let studentMessage={
name:'张三',
age:34,
parents:{
mother:'李四',
father:'王五'
},
friends:['Tom','jack']
}
studentMessage=getProxyData(studentMessage)
console.log(studentMessage)
studentMessage.age=56
studentMessage.parents.mother='阿娇'
studentMessage.friends[0]='阿坤'
PS C:\Users\Administrator\Desktop\简单测试\proxy的使用> node .\proxy.js
//打印studentMessage
{
name: '张三',
age: 34,
parents: { mother: '李四', father: '王五' },
friends: [ 'Tom', 'jack' ]
}
//修改studentMessage.age
{
name: '张三',
age: 34,
parents: { mother: '李四', father: '王五' },
friends: [ 'Tom', 'jack' ]
}
age
56
//修改studentMessage.parents.mother
{
name: '张三',
age: 56,
parents: { mother: '李四', father: '王五' },
friends: [ 'Tom', 'jack' ]
}
parents
{ mother: '李四', father: '王五' }
mother
阿娇
//修改stuentMessage.friends[0]
{
name: '张三',
age: 56,
parents: { mother: '阿娇', father: '王五' },
friends: [ 'Tom', 'jack' ]
}
friends
[ 'Tom', 'jack' ]
0
阿坤
C++代码生成Node原生模块
配置环境
- 安装VS Installer
- 安装VS Community
- 安装C++桌面开发环境
- 安装python
- 配置环境变量
- npm i -g node-gyp
编写C++代码
Test.cpp
#include <node.h>
#include <iostream>
void MyFunction(const v8::FunctionCallbackInfo<v8::Value>& args) {
std::cout << "Hello, world!" << std::endl;
}
void Init(v8::Local<v8::Object> exports) {
NODE_SET_METHOD(exports, "myFunction", MyFunction);
}
NODE_MODULE(addon, Init)
编写配置文件
binding.gyp
{
"targets": [
{
"target_name": "addon",
"sources": ["Test.cpp"]
}
]
}
编写运行代码
Test.js
const addon = require('./build/Release/addon');
addon.myFunction();
构建
- node-gyp configure
- node-gyp build
目录结构
> build
> binding.gyp
> Test.cpp
> Test.js
正则
正则对象regex与字符串A的关系
- 字符串A中寻找,满足正则对象regex规则的首个子串
- 字符串A中寻找,满足正则对象regex规则的所有子串
普通字符
- [2sJ70]:匹配[]中的任意字符
- [a-z]:匹配a到z中,任意字符
- [a-z0-9]:匹配a到z,0到9中,任意字符
- \d:数字
- \s:空白字符
- .:任意字符
需要转义的字符
^ ,$, {}, [],(),?,+,*,.,|,\
限定次数符
- {n}:需要匹配n次
- {n,}:需要匹配至少n次
- {n,m}:需要匹配至少n,至多m次
- ?:需要匹配0或1次
- +:需要匹配至少1次
- *:需要匹配0次或至少1次
- .*、.+:默认开启贪婪模式
- .*?、.+?:关闭贪婪模式
定位符
- ^:匹配字符串A的首部
- $:匹配字符串A的尾部
选择符和分组符
- ():分组符,每一个分组的值都会被保存到捕获组里。
- |:在()号范围内|号左右的正则表达式满足一个,匹配成功
举例:
正则表达式:/(a|B)(s|[123])/
字符串:10as01 结果:匹配成功
字符串:10B201 结果:匹配成功
修饰符
- g:开启全局模式
- i:忽略大小写
- m:多行匹配
集合
全面的Java
- Array:长度固定、类型固定、元素可以重复
- List:长度不固定、类型不固定、元素可以重复
- Set:长度不固定、类型不固定、元素去重
- Map:长度不固定、类型不固定、key值去重
- 实例对象:长度固定、类型固定、属性值去重
- 迭代器:iterator,enumeration
- 通过包装类实现存储基本数据类型
- Java8提供了Stream API,使得Java集合拥有和JS数组类似的方法
for迭代器
for(类型 元素:数组){}
数组.forEach(元素->{})
for(类型 元素:单列集合){}
单列集合.forEach(元素->{})
map.forEach((value,key)->{})
map.keySet()
map.values()
map.entrySet()
精炼的JS
- 数组=Array+List:长度不固定、类型不固定、元素可以重复
- Set:长度不固定、类型不固定、元素去重
- Map:长度不固定、类型不固定、key值去重
- 实例对象:长度不固定、类型不固定、属性值去重、属性值是字符串或Symbol
let obj={
key1:value1, //key1当成字符串解析
"key2":value2, //key2当成字符串解析
[key3]:value3 //key3当成变量解析
}
Set集合 | Map集合 | |
增 | add | set |
删 | delete clear | delete clear |
改 | / | replace |
查 | has size | has、get size |
Array.from | Array.from |
遍历方式
- for of:遍历对象的Symbol.iterator属性
- for in:遍历对象的可枚举属性
- for( ...; ...; ... ):依据索引遍历对象
- forEach:见JavaScript1底层封装讲解
数组 | for(let 元素 of 数组){} 数组.forEach(元素=>{}) for(let 索引 in 数组){} |
Set集合 | for(let 元素 of set集合) set集合.forEach(元素=>{}) |
对象 | Object.keys(对象) Object.values(对象) Object.entries(对象) for(let key in 对象){} for(let yield的值 of 对象){} |
Map集合 | Map集合.forEach((value,key)=>{}) map.keys()、map.values()、map.entries() |
IO流/File
IO流概述
- 程序的内存当成人脑
- 外部的数据通过输入流(inputstream)进入人脑
- 人脑的数据通过输出流(outputstream)进入外部
- 人阅读(read)从外界获得数据
- 人书写(write)向外界传递数据
IO流 | |
Js | 内置模块fs |
Java | 字节流(InputStream、OutputStream) 字符流(Reader、Writer) |
fs模块
一次性读入 | fs.readFile('文件路径','utf8',(err,数据)=>{}) let 数据=fs.readFileSync('文件路径','utf8') |
流式读入 | const stream=fs.createReadStream('文件路径',{encoding:"utf8"}) stream.on("data",(chunk)=>{...}) stream.on('end',()=>{...}) stream.on('error',(err)=>{...}) |
覆盖式写出 | fs.writeFile(文件路径, 数据, 'utf8', (err)=>{}) fs.writeFileSync(文件路径, 数据, 'utf8') |
追加式写出 | fs.appendFile(文件路径, 数据, 'utf8', (err)=>{}) fs.appendFileSync(文件路径, 数据, 'utf8') |
流式写出 | const stream=fs.createWriteStream("文件名",{encoding:"utf8"}) stream.on("finish",()=>{...}) stream.on('error',(err)=>{...}) stream.wirte("xxx") stream.wirte("yyy") stream.end() |
创建目录 | fs.mkdir(目录路径, (err)=>{}) fs.mkdirSync(目录路径) |
删除文件 | fs.unlink(文件路径, (err)=>{}) fs.unlinkSync(文件路径) |
删除目录 | fs.rmdir(目录路径,(err)=>{}) fs.rmdirSync(目录路径) |
重命名 | fs.rename(旧路径名称, 新路径名称, (err)=>{}) fs.renameSync(旧路径名称, 新路径名称) |
目录内容 | fs.readdir(目录路径,(err,文件&&目录数组)=>{}) let 文件&&目录数组=fs.readdirSync(目录路径) |
文件||目录信息 | fs.statSync(文件||目录信息) |
采用相对路径时,是相对于nodejs进程的运行目录
readline模块
import readline from 'readline'
const rl = readline.createInterface({
input: 输入流,
output: 输出流,
prompt: '输入提示符'
});
rl.on('line', (line) => {...})
rl.on('close', () => {...})
Socket通信
TCP | 服务端监听 客户端连接 客户端与服务端通信 双方断开连接 |
UDP | 双方开启监听 无需建立连接 发送方想发就发,接收方能接就接 |
Node&dgram&UDP
UDP端口1
import dgram from 'dgram'
const server = dgram.createSocket('udp4');
server.on('message', (msg, rinfo) => {
console.log(`Received message from ${rinfo.address}:${rinfo.port}: ${msg}`);
});
server.on('listening', () => {
const address = server.address();
console.log(`UDP server listening on ${address.address}:${address.port}`);
});
const PORT = 3000;
server.bind(PORT);
UDP端口2
import dgram from 'dgram'
const client = dgram.createSocket('udp4');
const message = Buffer.from('Hello, server!');
client.send(message, 0, message.length, 3000, 'localhost', (err) => {
client.close();
});
Node&net&TCP
服务端
import net from 'net');
const server = net.createServer((socket) => {
console.log('New client connected.');
socket.on('data', (data) => {
console.log(`Received data: ${data}`);
socket.write('Server response');
});
socket.on('end', () => {
console.log('Client disconnected.');
});
});
const PORT = 3000;
server.listen(PORT, () => {
console.log(`Server listening on port ${PORT}`);
});
客户端
import net from 'net'
const client = net.createConnection({ port: 3000 }, () => {
console.log('Connected to server.');
client.write('Hello server');
});
client.on('data', (data) => {
console.log(`Received data: ${data}`);
client.end();
});
client.on('end', () => {
console.log('Disconnected from server.');
});