node文件中可以直接访问的:
process 进程
buffer 缓冲区
clearImmediate setImmediate
clearTimeout
...
...
js获取页面上的所有标签
new Set([...document.querySelectorAll('*')].map(v => v.tagName));
15732892883 正则变成这样 157xxxx2883
let str = '15732892883'
console.log(str.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2'));
在命令行配置process.env环境变量:
mac中使用 export NODE_ENV=dev
windows中使用 set NODE_ENV=dev
所以就会出现一些第三方包去处理这些兼容性的问题
node基于common.js
node中一个文件就是一个模块(其实是一个闭包自执行函数)
(function (exports require module __filename, __dirname) {})()
node中自己写的模块需要使用相对路径进行引用
注意他们之间的关系
module.exports = exports = this = {}
require方法具有缓冲功能,多次引用只会执行一次
npm的一些操作:
npm root -g // 查看全局模块的安装位置
npm list --depth=0 -g //查看全局都安装了那些包
nrm //快速切换npm的源
nvm // 快速切换node的版本, mac下有个n命令也能切换
nrm 的简单实用
http-server
帮我们启动一个本地服务,类似这样的能提供服务还有live-server
npm install -g http-server
http-server //在某个路径下启动服务
node中读取文件怎么样更加优雅
1. 自己写一个函数封装成promise
const fs = require('fs')
function read (url) {
return new Promise((resolve, reject) => {
fs.readFile(url, 'utf8', function (err, data) {
if(err) return reject(err)
resolve(data)
})
})
}
read('./b.js').then(res => {
console.log(res)
}, err => {
console.log(err)
})
2.利用node中的util中的promisify,将异步分装为promise
const fs = require('fs')
const util = require('util');
let read = util.promisify(fs.readFile) //处理成了promise
read('./b.js','utf8').then(res => {
console.log(res);
}, err => {
console.log(res)
})
3. 在2的基础上用async 和 await 更加优雅
async function result () {
let content1 = await read('./a.js')
let content2 = await read('./b.js')
let str = content1 + content2
console.log(str)
}
node递归创建目录
const fs = require('fs')
function makep (url, cb) {
let urlArr = url.split('/');
let index = 0;
function make (path) {
if(urlArr.length < index) return cb('创建完成')
fs.stat(path, function (err) {
if (err) { //如果不在这个目录
fs.mkdir(path, function (err) {
if(err) return cb(err)
make(urlArr.slice(0, ++index+1).join('/'))
})
} else {// 如果存在就跳到下一次创建
make(urlArr.slice(0, ++index+1).join('/'))
}
})
}
make(urlArr[index])
}
makep('./aa/bb/cc', function (e) {
console.log(e)
})
path模块下path.resolve() 和 path.join()区别
这两者都是用来组装路径的
path.join 产生**相对**路径
console.log(path.join('/a', './img/so')); // \a\img\so
path.join也能产生**绝对**路径用__dirname拼接
console.log(path.join(__dirname, './img/so')); // F:\gongzuo\test\img\so
path.resolve 产生的是**绝对**路径
console.log(path.resolve('a', './img/so')); // F:\gongzuo\test\a\img\so
发布订阅模式
node中已经很好的实现了发布订阅 http://nodejs.cn/api/events.html
node中的实现
// 引入node的内置模块
let EventEmitter = require('events');
let {inherits} = require('util')
function Dog() {}
inherits(Dog, EventEmitter) // 相当于Dog.prototype.__proto__ = EventEmitter.prototype
let pup = new Dog()
// 订阅
pup.on('dark', () => {
console.log('旺旺')
})
// 发布
pup.emit('dark')
自己实现一下
class EventEmitter {
constructor() {
this._event = {}
}
// 订阅
on (eventName, cb) {
if(this._event[eventName]){
this._event[eventName].push(cb)
} else {
this._event[eventName] = [cb]
}
}
// 发布
emit (eventName, ...args) {
if(this._event[eventName]) {
this._event[eventName].forEach(fn => fn(...args))
}
}
// 移除某个订阅
removeListener (eventName, cb) {
if(this._event[eventName]) {
this._event[eventName] = this._event[eventName].filter(fn => fn !== cb)
}
}
// 实现once执行一次
once (eventName, cb) {
let fn = (...args) => {
cb(...args)
this.removeListener(eventName, fn)
}
this.on(eventName, fn)
}
}
//利用once只订阅一次
let event = new EventEmitter()
// 触发一次
event.once('cry', (mode) => {
console.log(`哭的模式:${mode}`)
})
// 发布(触发)哭操作
event.emit('cry', '大哭')
event.emit('cry', '大哭')
md中的折叠语法
<details>
<summary>内容描述</summary>
这里是具体的内容描述
</details>
<details>
<summary>内容描述</summary>
<md>这里是具体的内容描述</md>
</details>
Array.from()
Array.from()方法就是将一个类数组对象或者可遍历对象转换成一个真正的数组。
将类数组对象转换为真正数组:
let arrayLike = {
0: 'tom',
1: '65',
2: '男',
3: ['jane','john','Mary'],
'length': 4
}
let arr = Array.from(arrayLike)
console.log(arr) // ['tom','65','男',['jane','john','Mary']]
结果
那么,如果将上面代码中length属性去掉呢?实践证明,答案会是一个长度为0的空数组。
这里将代码再改一下,就是具有length属性,但是对象的属性名不再是数字类型的,而是其他字符串型的,代码如下:
let arrayLike = {
'name': 'tom',
'age': '65',
'sex': '男',
'friends': ['jane','john','Mary'],
length: 4
}
let arr = Array.from(arrayLike)
console.log(arr) // [ undefined, undefined, undefined, undefined ]
会发现结果是长度为4,元素均为undefined的数组
由此可见,要将一个类数组对象转换为一个真正的数组,必须具备以下条件:
- 该类数组对象必须具有length属性,用于指定数组的长度。如果没有length属性,那么转换后的数组是一个空数组。
- 该类数组对象的属性名必须为数值型或字符串型的数字
将Set结构的数据转换为真正的数组:
let arr = [12,45,97,9797,564,134,45642]
let set = new Set(arr)
console.log(Array.from(set)) // [ 12, 45, 97, 9797, 564, 134, 45642 ]
Array.from还可以接受第二个参数,作用类似于数组的map方法,用来对每个元素进行处理,将处理后的值放入返回的数组。如下
let arr = [1,2,3,4,5,6,7]
let set = new Set(arr)
console.log(Array.from(set, item => item + 1)) // [ 2, 3, 4, 5, 6, 7, 8 ]
去除字符串里面的重复字符
console.log([...new Set('abcddd')].join(''));
// abcd
数组去重
function dedupe(array) {
// return Array.from(new Set(array)); 这种通过Array.from
return [...new Set(array)]; // 这种通过解构
}
dedupe([1, 1, 2, 3]) // [1, 2, 3]
求数组的并集
let a = [1, 2, 3];
let b = [4, 3, 2];
// 并集
let union = [...new Set([...a, ...b])];
console.log(union); //[1, 2, 3, 4]
求数组的交集与差集
let a = [1, 2, 3];
let b = new Set([4, 3, 2]);
// 交集
let intersect = [...new Set(a.filter(x => b.has(x)))];
console.log(intersect); // [2,3]
// 差集
let difference = [...new Set(a.filter(x => !b.has(x)))];
console.log(difference); //[1]
slice(0) 是深拷贝还是浅拷贝
- 当数组中的元素都是非引用类型时: 可以实现深拷贝
let arr = [1,2,3,4]
let human = arr.slice(0);
human[0] = 'nanfeiyan';
console.log(arr) // [ 1, 2, 3, 4 ]
console.log(human) //[ 'nanfeiyan', 2, 3, 4 ]
- 当数组中的元素有引用类型时: 不可以实现深拷贝
var obj = [
{
name:'melin1',
job:'111'
},
{
name:'melin2',
job:'222'
},
{
name:'melin3',
job:'333'
}
];
var copy = obj.slice(0);
copy[1].name = 'tom';
console.log(obj[1].name); //tom
console.log(copy[1].name); //tom
for in 和 for of的区别
for in
let arr = [1,2,3,5,6,3];
arr.name = 'liguigong';
Array.prototype.jj = function () {
console.log(230)
}
for(let i in arr) {
console.log(i)
}
结果:
for of
因为能够被for...of正常遍历的,都需要实现一个迭代器Iterator,
而数组、字符串、Set、Map和NodeList结构,早就内置好了Iterator(迭代器),它们的原型中都有一个Symbol.iterator方法, 而Object对象并没有实现这个接口,使得它无法被for...of遍历
Array.prototype[Symbol.iterator];
// ƒ values() { [native code] }
String.prototype[Symbol.iterator];
// ƒ [Symbol.iterator]() { [native code] }
Set.prototype[Symbol.iterator];
// ƒ values() { [native code] }
Map.prototype[Symbol.iterator];
// ƒ entries() { [native code] }
NodeList.prototype[Symbol.iterator];
// ƒ entries() { [native code] }
Object.prototype[Symbol.iterator];
// undefined
如果想遍历Object类型怎么操作,给对象加上遍历器
let obj = {
name: "XX",
age: 20,
job: 'teacher',
[Symbol.iterator]() {
const self = this;
const keys = Object.keys(self);
let index = 0;
return {
next() {
if (index < keys.length) {
return {
value: self[keys[index++]],
done: false
};
} else {
return { value: undefined, done: true };
}
}
};
}
};
for (let item of obj) {
console.log(item)
}
// XX 20 teacher
git的一些操作:
git stash //将此时更改的内容暂存起来(此时就可以切换到其他分支就行操作了,
等处理完在切回本分支(git checkout 分支名), 还原以前的,继续操作)
git stash apply //恢复却不删除stash的内容
git stash pop //恢复并且删除stash信息
git stash list // 查看此时的暂存列表
git stash drop // 删除这个分支上的所有的stash
git checkout . 和 git reset 和 git reset --hard 提交信息编号之间的区别
git checkout . //将工作区的代码恢复到上一次commit之前
git reset . //将暂存区的内容恢复到工作区
git reset --hard 提交信息编号之间的区别 //回到指定的版本
git add . //将工作区的内容添加到暂存区
git add . 和 git reset . 是相反的两对
git fetch和git pull的区别
git fetch 相当于是从远程获取最新到本地,不会自动merge
git pull:相当于是从远程获取最新版本并merge到本地
git pull 相当于从远程获取最新版本并merge到本地
在实际使用中,git fetch更安全一些