位运算
按位操作符:0或者1之间的运算
a|b 或
任意一个为1结果为1
console.log(0 | 1) //1
console.log(1 | 0) //1
console.log(1 | 1)//1
a&b 与
两个同时为1结果为1
console.log(1 & 1) //1
a^b 异或
有且只有一个为1时,结果才为1
console.log(1 ^ 0)//1
console.log(0 ^ 1)//1
~a 非
即0变成1
即1变成0
~1 //0
~0 //1
a>>b 右移
将运算数的二进制整体右移指定位数,整数高位用0补齐,附属高数用1补齐
10/2 //5
10>>1 //5
a<<1 左移
10*2 //20
10<<2 //20
~~n 取反
~~n 来替代Math.floor(n)或者parseInt(n,10)
n|n n&n ~~n 的作用相同
将正数转换为二进制
let numbers=5
numbers.toString(2)
交换两个数可以用^=
a,b
a^=b
b^=a
a^=b
带有string 的逻辑操作
console.log('a'&&'b'&&'c') // 'c'
console.log('a' && 'b' || 'c') // 'b'
call和apply和bind等改变this指向
let a = [1, 2, 3]
let b = [4, 5, 6];
let c = {}
[].push.apply(a, b)
console.log(a)
//[ 1, 2, 3, 4, 5, 6 ]
[].push.apply(c,b)
console.log(c)
//{ '0': 4, '1': 5, '2': 6, length: 3 } 类数组
[].push.call(a, ...b)
console.log(a)
//[ 1, 2, 3, 4, 5, 6 ]
[].push.call(c,...b)
console.log(c)
//{ '0': 4, '1': 5, '2': 6, length: 3 }
bind()也是改变this的指向,但是返回的是一个函数
但是如果用this就别用箭头函数了
function add(c, d) {
return this.a + this.b + c + d;
}
const o = {a: 1, b: 3}
console.log(add.call(o, 5, 7)) //16
console.log(add.apply(o, [10, 20])) //34
console.log(add.bind(o, 5, 7)())//16
ES10
let arr=[1,2,3,[4,5,6,[7,8,9,[1,2,3]]]]
console.log(arr.flat(1))
//[1, 2, 3, 4, 5, 6, Array(4)]
console.log(arr.flat(Infinity))
//[1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3]
const map = new Map([['a', 1], ['b', 2]]);
Object.fromEntries(map); // => { a: 1, b: 2 }
copyWithin() 浅复制数组的一部分到同一数组的另一个位置,不会改变数组的长度
参数
target(必需):从该位置开始替换数据
start(可选):
end(可选)
console.log([1, 2, 3, 4, 5,6,7].copyWithin(0, 3, 5))
//0 是目标元素0的位置
//[3,5] 包左不包右 ,替换到0位置
//因为不改变数组的长度,所有只替换前面两位[4,5,3,4,5,6,7]
let numbers = [1, 2, 3, 4, 5];
numbers.copyWithin(-2);//[1,2,3,1,2]
numbers.copyWithin(-2, -3, -1);
//// [1, 2, 3, 3, 4] [-3,-1]
// console.log([1, 2, 3, 4, 5].slice(-3, -1)) //3,4
[1, 2, 3, 4, 5].copyWithin(0, 3); // => [4, 5, 3, 4, 5]
flatMap()
console.log([{a: 1, b: 2}, {a: 3, b: 4}, {a: 5, b: 6}].flatMap(it => [it.a, it.b]))
// => [1, 2, 3, 4, 5, 6]
core.js中有意思的代码
let object = {
[Symbol.toStringTag]: 'Foo'
};
'' + object; // => '[object Foo]'
Object.keys('qwe'); // => ['0', '1', '2']
for (let [key, value] of Object.entries({ a: 1, b: 2, c: 3 })) {
console.log(key); // => 'a', 'b', 'c'
console.log(value); // => 1, 2, 3
}
let objects={a:1}
Object.defineProperty(objects,'b',{value:2})
objects[Symbol('c')]=3;
console.log(Object.keys(objects))
//['a']
console.log(Reflect.ownKeys(objects))
//[ 'a', 'b', Symbol(c) ]
**map**
let array = [1];
let map = new Map([['a', 1], [42, 2]]);
map.set(array, 3).set(true, 4);
console.log(map.size); // => 4
console.log(map.has(array)); // => true
console.log(map.has([1])); // => false
console.log(map.get(array)); // => 3
map.forEach((val, key) => {
console.log(val); // => 1, 2, 3, 4
console.log(key); // => 'a', 42, [1], true
});
map.delete(array);
console.log(map.size); // => 3
console.log(map.get(array)); // => undefined
console.log(Array.from(map)); // => [['a', 1], [42, 2], [true, 4]]
let map = new Map([['a', 1], ['b', 2], ['c', 3]]);
for (let [key, value] of map) {
console.log(key); // => 'a', 'b', 'c'
console.log(value); // => 1, 2, 3
}
for (let value of map.values()) console.log(value); // => 1, 2, 3
for (let key of map.keys()) console.log(key); // => 'a', 'b', 'c'
for (let [key, value] of map.entries()) {
console.log(key); // => 'a', 'b', 'c'
console.log(value); // => 1, 2, 3
}
map的forEach的第一个参数val第二个参数key
进制之间的转化
let a=10
//十进制转成二进制
console.log(a.toString(2))
//1010
//十进制转成8进制
console.log(a.toString(8))
//12
//十进制转成16进制
let b=20;
console.log(b.toString(16))
//14
console.log(parseInt('1010', 2))
console.log(Number('0b1010'))//二进制转成十进制
0b 二进制 0o 八进制 0x 十六进制
Promise
const sleepRandom=trim=>{
return new Promise(res=>res(trim))
}
sleepRandom(23).then(res=>{
console.log(res)
})
Promise.all(['foo',sleepRandom(23),sleepRandom(43)]).then(res=>{
console.log(res)
//[ 'foo', 23, 43 ]
})
Promise.race()
如果迭代包含一个或多个非承诺值和/或已解决/拒绝的承诺,则
Promise.race
将解析为迭代中找到的第一个值。
var resolvedPromisesArray = [Promise.resolve(33), Promise.resolve(44)];
var p = Promise.race(resolvedPromisesArray);
p.then(res=>{
console.log(res) //33
})
var p1 = new Promise(function(resolve, reject) {
setTimeout(resolve, 500, "one");
});
var p2 = new Promise(function(resolve, reject) {
setTimeout(resolve, 100, "two");
});
Promise.race([p1, p2]).then(function(value) {
console.log(value); // "two"
// 两个都完成,但 p2 更快
});
RXjs
异步数据流编程
Observable
一个可调用的未来值或事件的集合
Subscription
主要用于取消 Observable的执行
Operators
采用函数式编程风格的纯函数所有的操作符在pipe管道中执行 let foo=new Observable(observable=>{ observable.next(23) }); foo.subscribe(x=>{ console.log(x) }); import {Observable,fromEvent} from 'rxjs'; const button = document.querySelector('.button') fromEvent(button,'click').subscribe(res=>{ console.log(1) }) //多值推送 const observale=new Observable(observable=>{ observable.next('hi'); observable.next('woshi'); observable.next('hello world'); observable.complete(); }); observale.subscribe({ next:value=>{ console.log(value) }, error:err=>{ console.log(err) }, complete:()=>{ console.log('done!') } })
map
import { interval } from 'rxjs'; import { mapTo } from 'rxjs/operators'; from([1,2,3,4]).pipe(map(val=>val+10)).subscribe(res=>{ console.log(res) //1,2,3,4 }) from([ { name: 'Joe', age: 30 }, { name: 'Frank', age: 20 }, { name: 'Ryan', age: 50 } ]).pipe(map(({name})=>name)).subscribe(res=>{ console.log(res) /*Joe Frank Ryan*/ })
嫖客的源码之路
let i=-1
!~i //true
!!~-1 //false
清楚字符串的空格
replace(/^s+|s+/g, '')
is.js 源码
Object.prototype.toString.call()
arguments 带入的结果为 '[object Arguments]'
类数组转成数组
Object.prototype.slice.call()
判断arguments
is.arguments = function(value) { // fallback check is for IE
return toString.call(value) === '[object Arguments]' ||
(value != null && typeof value === 'object' && 'callee' in value);
};
arguments里面有'callee'属性
判断undefined
console.log(undefined == void 0)
判断是不是对象
let a={name:'sss'}
console.log(Object(a) === a)
判断 对象,数组,string是否为空
const empty = function (value) {
if (Object(value)===value) {
var length = Reflect.ownKeys(value).length;
//length==0判断的是空对象
//属性length=1&&Array.isArray()判断数组
//length==2&&... 判断arguments
if (length === 0 || (length === 1 && Array.isArray(value)) ||
(length === 2 && Object.prototype.toString.call(value) === '[object Arguments]')) {
return true;
}
return false;
}
//判断是string
return value === '';
};
const endWith = (str, target) => {
if (typeof str !== 'string') {
return false
}
target += '';
let diff = str.length - target.length
return diff >= 0 && str.indexOf(target, diff) === diff;
}
console.log(endWith('abcder', 'er'))//true
const startWith = (str, target) => {
return typeof str === 'string' && str.indexOf(target) === 0
}
const comparator = {
'<': (a, b) => a < b,
'<=': (a, b) => a <= b,
'>': (a, b) => a > b,
'>=': (a, b) => a >= b
}
const sorted = (array, sign = '<') => {
if (!Array.isArray(array)) {
return false
}
let fn = comparator[sign]
for (let i = 1; i < array.length; i++) {
if (!fn(array[i - 1], array[i])) {
return false
}
}
return true
}
console.log(sorted([1, 2, 3, 3,4],'<='))
matter.js
2D物理引擎
611 有效三角形的个数
const triangleNumber = nums => {
nums.sort((a, b) => a - b)
let result = 0
for (let i = nums.length - 1; i >= 2; i--) {
let l = 0
let r = i - 1
while (l < r) {
if (nums[l] + nums[r] > nums[i]) {
result += r - l
r--
} else {
l++
}
}
}
return result
}
Moment.js源码
今天是这一年的第几天
Math.floor(
(new Date() - new Date(new Date().getFullYear(), 0, 0)) / 1000 / 60 / 60 / 24
)
getFullYear() 获取年份
console.log(new Date().toISOString())
//2019-08-13T02:44:08.020Z
getDay() //星期几 日-六(0-6)
let full=new Date().getFullYear()
let month=new Date().getMonth()+1
//今天是多少号 getDate()
console.log(new Date().getDate())
//这个月有多少天
let day=new Date(full,month,0).getDate()
算一个数组中最小的那个日期
const array = [
new Date(2017, 4, 13),
new Date(2018, 2, 12),
new Date(2016, 0, 10),
new Date(2016, 0, 9),
];
new Date(Math.min.apply(null, array)).toISOString();
// => "2016-01-08T13:00:00.000Z"
当前时间加上一个星期
let day=new Date().getDate()+7
//设置多少号
console.log(new Date(new Date().setDate(day)))
//2019-08-20T03:14:45.883Z
//另一种方法
console.log(new Date(new Date().getTime() + 1000 * 60 * 60 * 24 * 7))
判断两个时间的大小
console.log(new Date(2010, 10, 20) < new Date(2010, 10, 21))
原生技巧
H5标签
<time> 标签定义日期或时间,或者两者。
<p>
我们在每天早上 <time>9:00</time> 开始营业。
</p>
<p>
我在 <time datetime="2008-02-14">情人节</time> 有个约会。
</p>
calc(100%-(100px*2))
font-size: calc(100vw / 30);
:nth-child(odd)好于 :nth-child(2n+1)
odd 奇数 even 偶数
css我已经忘得差不多啦
transition 过渡, transfrom:translateX(100px) 移动
发现一个神奇的技能
如果是求值,就可以用reduce,进行迭代函数求值
const plus1 = a => a + 1;
const mult2 = a => a * 2;
const pipe = (...args) => val => args.reduce((a, b) => b(a), val)
console.log(pipe(plus1,mult2)(10))
//22
分组
const consecutive = (arr, num) => {
let acc = [];
for (let i = 0; i < arr.length; i++) {
for (let j = arr.length - 1; j >= 1 && i !== j; j--) {
if (arr.slice(i, j).length == num) {
acc.push(arr.slice(i, j))
}
}
}
return acc
}
console.log(consecutive([1, 2, 3, 4, 5, 6], 1))
//[ [ 1, 2 ], [ 2, 3 ], [ 3, 4 ], [ 4, 5 ] ]
对象改成url
let obj = {
foo: 1,
bar: 2
};
const joins = (obj, str) =>
Object.keys(obj)
.reduce((acc, val) => acc.concat(val + '=' + obj[val]), [])
.join(str);
console.log(joins(obj, '&'))
//foo=1&bar=2
判断是不是对象
const isObject=obj=>obj&&obj.constructor===Object;
//判断对象或函数
const isObjFn=obj=>(/function|object/).test(typeof obj)&&obj!=null
const isObject=data=>typeof data==='object'&&
!Array.isArray(data)&&data!==null;
const isEqual = (a, b) => a === b || (a !== a && b !== b)
// console.log(isEqual(NaN, NaN)) //true
掘金的优秀文章
https://github.com/zenghongtu/Blog/issues/1
33-js-concepts
https://github.com/stephentian/33-js-concepts
奇妙的js jsfuck
https://github.com/aemkei/jsfuck/blob/master/jsfuck.js
查看原始包装的函数
0['constructor'] //[Function: Number]
""['constructor'] //[Function: String]
console.log(''.constructor) //[Function: String]
使用+[] 将他们转换成字符串
console.log(''.constructor+[])
//function String() { [native code] }
console.log([].find ['constructor'])
//[Function: Function]
Array.from
const crossJoin = (a, b) => Array.from({ length: a.length }, (v, i) => [a[i], b[i]]);
const crossJoin = (a, b) => Array.from(a, (v, i) => [v, b[i]]);
console.log(crossJoin(['a', 'b', 'c'], ['g', 'd', 'h']))
//[ [ 'a', 'g' ], [ 'b', 'd' ], [ 'c', 'h' ] ]
leetCode 896 单调数列
单调递增或者单调递减返回true,否则返回false
const monotonous = items => { if (items.length <= 1) { return true } let n = items.length - 1 if (items[0] < items[n]) { //升序 for (let i = 1; i <= n; i++) { if (items[i - 1] > items[i]) { return false } } }else{ //降序 for (let i = 0; i <=n ; i++) { if (items[i - 1] < items[i]) { return false } } } return true } //精简版 const monotonous = items => { if (items.length <= 1) { return true } let a = 0, b = 0; for (let i = 1; i < items.length; i++) { a += items[i - 1] < items[i]; b += items[i - 1] > items[i]; } return !(a && b); }
timeage.js源码分析(几分钟前,几秒前)
自执行函数
let sum=(i=>i*2)((i=>i+2)(1))
console.log(sum)
//1=>i+2=>i*2 =>(1+2)*3=6
//参数:一个是开始的时间,一个是之后的时间
var format = function format(date, nowDate) {
//计算前后的时间差,精确到s
const sec = diffSec(date, nowDate)
return formatDiff(sec, zh_CN);
};
var diffSec = function diffSec(date, nowDate) {
//如果没有设置后面的时间,就是当前时间
nowDate = nowDate ? toDate(nowDate) : new Date();
return (nowDate - toDate(date)) / 1000;
};
//取年份 new Date('2019')
var toInt = function toInt(f) {
return parseInt(f);
};
//时间转化
var toDate = function toDate(input) {
if (input instanceof Date) return input;
//如果全部是数字,就取年份
if (!isNaN(input) || /^d+$/.test(input)) return new Date(toInt(input));
input = (input || '').trim()
.replace(/.d+/, '') // remove milliseconds
.replace(/-/, '/')
.replace(/-/, '/')
.replace(/(d)T(d)/, '$1 $2')
.replace(/Z/, ' UTC') // 2017-2-5T3:57:52Z -> 2017-2-5 3:57:52UTC
.replace(/([+-]dd):?(dd)/, ' $1$2'); // -04:00 -> -0400
return new Date(input);
};
console.log(toDate('2019.12.12 12:12:12'))
//2019-12-01T04:12:12.000Z
console.log(toInt('2019.12.12 12:12:12'))
//2019
console.log(new Date('2019'))
//2019-01-01T00:00:00.000Z
//第一个参数是时间差,第二个参数是函数(计算几s前)
function formatDiff(diff, localeFunc) {
var i = 0,
agoin = diff < 0 ? 1 : 0,
// timein or timeago
total_sec = diff = Math.abs(diff);
//计算时间
for (; diff >= SEC_ARRAY[i] && i < SEC_ARRAY.length; i++) {
diff /= SEC_ARRAY[i];
}
diff = toInt(diff);
i *= 2;
if (diff > (i === 0 ? 9 : 1)) i += 1;
return localeFunc(diff, i, total_sec)[agoin].replace('%s', diff);
}
var ZH = '秒_分钟_小时_天_周_个月_年'.split('_');
var SEC_ARRAY = [60, 60, 24, 7, 365 / 7 / 12, 12];
//组成 %s 秒前的大数组
function zh_CN(number, index) {
if (index === 0) return ['刚刚', '片刻后'];
var unit = ZH[parseInt(index / 2)];
return [`${number}${unit}前`, `${number}${unit}后`];
};
console.log(format('2019-08-15', '2019-08-13'))