“Yeah It’s on. ”
正文
数字排序
Javascript 的sort()函数在默认情况下使用字母数字(字符串Unicode码点)排序。
所以[1,2,5,10].sort() 会输出 [1, 10, 2, 5]. 要正确的排序一个数组, 你可以用 [1,2,5,10].sort((a, b) => a — b) 很简单的解决方案, 前提是你得知道有这么个坑
new Date()
- 没有参数: 返回当前时间
- 一个参数 x: 返回1970年1月1日 + x 毫秒。 了解 Unix 的人知道为什么。
- new Date(1, 1, 1) 返回 1901, 二月 , 1号。因为,第一个参数表示1900年加1年,第二个参数表示这一年的第二个月(因此是二月) — 脑回路正常的人会从1开始索引 — ,第三个参数很明显是这个月的第一天
- new Date(2016, 1, 1) 不会给1900年加上2016。它仅代表2016年。
Date.now() // 获取当前时间的毫秒数
- var dt = new Date() dt.getTime() // 获取毫秒数
- dt.getFullYear() // 年
- dt.getMonth() // 月 (0-11) 特别注意这里 实际应用的时候记得+1
- dt.getDate() //日 (0 - 31 )
- dt.getHours() //小时(0 - 23)
- dt.getMinutes() //分钟(0 - 59)
- dt.getSeconds() //秒(0 - 59)
Replace
let s = 'bob'
const replaced = s.replace('b','l')
console.log(replaced === 'lob') //true
console.log(s === 'bob') //true
replace 只会替换第一个匹配的字符串
如果你想替换所有匹配的字符串,你可以使用带/g标志的正则表达式 :
“bob”.replace(/b/g, ‘l’) === ‘lol’ // 替换所有匹配的字符串
比较的时候要注意
// These are ok
'abc' === 'abc' // true
1 === 1 // true
// These are not
[1,2,3] === [1,2,3] // false
{a: 1} === {a: 1} // false
{} === {} // false
闭包
const Greeters = []
for (var i = 0; i < 10; i++) {
Greeters.push(function () {
return console.log(i)
})
}
Greeters[0]() // 10
Greeters[1]() // 10
Greeters[2]() // 10
原因: i一直被引用 Greeters[0]只是一个函数
function (){
return console.log(i)
}
Greeters0这时候才会调用,此时i已经变为10了
怎样修改让它输出 0, 1, 2… ?
用let替代var解决 let和var的不同在于作用域。var的作用域是最近的函数块,let的作用域是最近的封闭块,封闭块可以小于函数块(如果不在任何块中,则let和var都是全局的)。
替代方法: 用 bind: Greeters.push(console.log.bind(null, i))
hasOwnProperty
var item
for(item in f){
// 高级浏览器已经在 for in 中屏蔽了来自原型的属性
// 但是为了程序的健壮性 建议加上
if(f.hasOwnProperty(item)) {
console.log(item)
}
}
Function.apply.bind()与Function.apply.bind()
https://blog.csdn.net/weixin_37787381/article/details/81509361
Promise.resolve([10,20]).then(Function.apply.bind(function(x, y){
console.log(x, y);
}, null)); // 10,20
Function.apply.bind(…)是个什么操作?
var sum = function(x, y) {
console.log(x, y);
}
var foo = Function.apply.bind(sum, null);
foo([10, 20]); // 10, 20
这里我们有一个函数sum,通过Function.apply.bind(sum, null)我们创建了一个新的函数foo(…)。
我们一步步分析Function.apply.bind(sum, null)这段代码。 sum.apply(null, [10, 20])这句代码将第一个参数置为null,第二个参数是一个数组,用于拆开后作为sum的最终参数。
对象引用的一个注意点
let option = {
aaa: {
a: "a",
b: "b"
},
bbb: "bbb"
}
let origin = option["aaa"] || {}
origin.a = "ccc"
console.log(origin, option)
// 输出结果
{a: "ccc", b: "b"}
{
aaa: {a: "ccc", b: "b"}
bbb: "bbb"
}
这里origin能正确引用到option[“aaa”]所以没有问题
当option.aaa 不存在时
let option = {
aaa: {
a: "a",
b: "b"
},
bbb: "bbb"
}
let origin = option["aaa"] || {}
origin.a = "ccc"
console.log(origin, option)
// 输出结果
{a: "ccc"}
{bbb: "bbb"}
origin无法正确引用到option[“aaa”],这是一个很严重的问题
那么,如何在option.aaa为空的情况下,使得origin可以正确引用到option[“aaa”]
有一个高级的写法,经常出现在框架源码中
let option = {
bbb: "bbb"
}
// 技巧:
let origin = option["aaa"] || (option["aaa"] = {})
origin.a = "ccc"
console.log(origin, option)
// 输出结果
{a: "ccc"}
{
aaa: {a: "ccc"}
bbb: "bbb"
}
实现一个简单watch
最近写小程序框架需要实现一个watch,于是就开始了手撸Object.defineProperty
function defineReactive(obj, key, customSetter) {
let val = obj[key]
Object.defineProperty(obj, key, {
set(newVal) {
// eslint-disable-line
if (newVal === val || (newVal !== newVal && val !== val)) {
return
}
customSetter(newVal, val)
},
})
}
watch: {
bannerList(newVal, oldVal) {
console.warn("111", "banner 111 watch", this, newVal, oldVal)
},
},
这里customSetter就是watch里的bannerList
存在一个非常严重的问题bannerList(newVal, oldVal)的oldVal一直不变
那么如何一个完善的watch要可以同时监听到旧值(oldVal)和新值(newVal)呢?
只需要增加一行代码。
function defineReactive(obj, key, customSetter) {
let val = obj[key]
Object.defineProperty(obj, key, {
set(newVal) {
// eslint-disable-line
if (newVal === val || (newVal !== newVal && val !== val)) {
return
}
customSetter(newVal, val)
val = newVal
},
})
}
val = newVal
也是一个小技巧,记录一下
条件中的递减
const _retry = (info, num) => {
if (!num) {
return reject(info);
}
setTimeout(() => {
fn(...args).then(
(res) => resolve(res),
// (rej) => _retry(rej, num--) 这种写法传进_retry的num还是原来的num
(rej) => _retry(rej, --num) // 正确写法
);
}, interval);
};
总结:在递归函数中递减 正确写法是 –num 而不是 num–
offsetWidth
offsetWidth实际获取的是盒模型(width+border + padding)
offsetX 触发到子元素
应该怎么解决?
解决方案1
在事件捕获阶段处理,阻止冒泡。 e.stopPropagation(); e.preventDefault();
解决方案2
判断元素 e.target === 父元素 时候获取
解决方案3(最好)
不使用offsetX
用event.pageX - xxx.getBoundingClientRect().left
在jquery中可以用event.pageX - xxx.offset().left