1、数组对象与数组/类数组 之间的互转
知识点:Object.entries()、Object.fromEntries()
假设vue表单验证有这样一个场景,在表单新增时,需要密码验证,但是编辑时不需要表单验证
const rules = {
loginName: [
{
required: true,
message: '请输入登录账号',
trigger: 'blur'
}
],
pwd: [
{
required: true,
validator: validatePwd,
trigger: 'blur'
}
]
}
如果我们使用 rule.pwd[0].required = false ,那么可以明确告诉你这不行,还是会进行验证,所以我们必须要将这个属性删掉,但是我们只是在编辑时候不需要,新增时候还是要要得,所以可以这样试试:
// 编辑
let tmp = Object.entries(rules).filter(item => {
return item[0] !== 'pwd'
})
let result = Object.fromEntries(tmp)
// 新增
let result = rules
// Object.entries() 是将对象的属性和值遍历出来,然后返回一个二维数组,
// 其中每个一维数组都是一个属性的键值对,而 Object.fromEntries()
// 则是上面操作的逆向操作, 是将数组转换成对象形式
2、条件判断时类型转换
我们代码里很多时候会使用 if 条件判断,然后条件很多时候会是数组 或者 对象, 那么你想过空数组 / 空对象 在这种情况会是啥样的吗?
知识点: 条件判断时类型转换
// 空数组
if ([]) {
console.log('true') => 'true'
}
// 空对象
if ({}) {
console.log('true') => 'true'
}
// 可以发现,空对象和空数组在这情况下,都会打印 'true', 为什么呢?
// 因为在条件判断时,会发生类型转换, 先转换成boolean类型,再进行
// 判断,数组和对象 其类型都是对象,对象转布尔,都会是 true,所以
// 我们平时在条件判断时,不要直接将数组或对象进行判断,数组的话,
// 我们可以
if (arr.length) {}
// 这种形式来判断是否是空数组
// 对象的话
if (Object.keys(obj).length)
// 这种形式来判断是否是空对象
但是还有种情况是,在if里面 作等于比较
if ([] === true) {
console.log('true')
}
// 进行等值转换时,都会先将数据的valueOf()值进行比较,
// 当valueOf()后的值不适合原始值,那么就再输出 toString()
// 进行比较,这里 数组的valueOf()输出是Object() { [native code] }
// 不是原始值(注:原始值就是基本数据类型),所以再进行
// arr.toString(),空数组则输出 '', 字符串与布尔值进行
// 比较时,都会转成Number类型, 因为 0 != 1, 所以这里不打印 'true'
if ({} === true) {
console.log('true')
}
// 对象的valueOf() 是它本身,然后再进行toString()和
// Number转换时,对象的数字转换值都是NaN, 因为NaN 不
// 与任何值相等,所以这里也不打印 'true'
3、JS的valueOf()
valueOf()是Object的原型方法,后续继承Object的如果没有重写此方法,那么默认用的是Object的valueIf方法,此方法没有参数喔,是通过 xxx.valueOf() 来调用
Object.prototype.valueOf()
对象返回的都是自身(无论是否是空对象)
let obj = {}; console.log(obj.valueOf())
输出: {}
let obj = {name: 'lindadayo'}; console.log(obj.valueOf())
输出:{name: 'lindadayo'}
Array.prototype.valueOf()
数组返回的都是自身(无论是否是空数组)
let arr = []; console.log(arr.valueOf())
输出: []
let arr = [1, 2, 3]; console.log(arr.valueOf())
输出:[1, 2, 3]
String.prototype.valueOf()
无论是字符对象,或是字符字面量,返回的都是字符串本身,跟toString()一致
let str = new String('hello lindadayo'); console.log(str.valueOf())
输出: 'hello lindadayo'
let str = 'hello lindadayo'; console.log(str.valueOf())
输出:'hello lindadayo'
Number.prototype.valueOf()
无论是数字对象,或是数字字面量,返回的都是数字本身
let num = new Number(2023); console.log(num.valueOf())
输出:2023
let num = 2023; console.log(num.valueOf())
输出:2023
Boolean.prototype.valueOf()
布尔对象,传参的值,转布尔类型后为true的话,那么返回值为true,否则的话,返回值为false,
布尔字面量,返回布尔值本身
let boolean = new Boolean(); console.log(boolean.valueOf())
输出:false
let boolean = new Boolean('林大大哟'); console.log(boolean.valueOf())
输出:true
let boolean = new Boolean(''); console.log(boolean.valueOf())
输出:false
let boolean = new Boolean(null); console.log(boolean.valueOf())
输出:false
let boolean = true; console.log(boolean.valueOf())
输出:true
Function.prototype.valueOf()
console.log(Function.valueOf())
输出: ƒ Function() { [native code] }
// 函数表达式
function hello(){
console.log('hello lindadayo')
}
console.log(hello.valueOf())
输出:
ƒ hello(){
console.log('hello lindadayo')
}
// 函数声明式
const hello = () => {
console.log('hello lindadayo')
}
console.log(hello.valueOf())
输出:
() => {
console.log('hello lindadayo')
}
Date.prototype.valueOf()
返回以数值格式表示的一个Date
对象的原始值。该值从1970年1月1日0时0分0秒(UTC,即协调世界时)到该日期对象所代表时间的毫秒数, 和Date.prototype.getTime()一样
let date = new Date(2023, 1, 14); console.log(date.valueOf())
输出:1676304000000
Symbol.prototype.valueOf()
Symbol 这是 js 新增类型,用的比较少,主要用来解决对象属性冲突的问题,即使Symbol传参相同,那么全等对比也是不一样的,用Symbol定义的类型,不会被Object.keys和其他发现,只有Reflect.ownKeys和Object.getOwnPropertySymbols能够找到这类型
const a = Symbol('hello')
const b = Symbol('hello')
console.log(a === b)
输出:false
null 和 undefined
都是没有valueOf和toString方法的
4、JS的toString()
Object.prototype.toString()
对象调用toString方法都是返回'[object Object]'
let obj = {}; console.log(obj.toString())
输出: '[object Object]'
let obj = {name: 'lindadayo'}; console.log(obj.toString())
输出:'[object Object]'
console.log(Object.toString())
输出: function Object() { [native code] }
console.log({a: 1}.toString())
输出:Uncaught SyntaxError: Unexpected xxx
console.log({a: 1}.toString())
输出:Uncaught SyntaxError: Unexpected xxx
Array.prototype.toString()
空数组调用toString方法,就会转为空字符,非空数组就会类似 arr.join() 转为字符串,对象数组的话,数组里的对象跟上面Object的toString()一样转换
let arr = []; console.log(arr.toString())
输出: ''
let arr = [1, 2, 3]; console.log(arr.toString())
输出:'1,2,3'
let arr = [{name: 'linda'}, {name: 'dayo'}]; console.log(arr.toString())
输出: '[object Object],[object Object]'
String.prototype.toString()
这个不解释了,就直接返回本身
Boolean.prototype.toString()
返回的是字符形式的布尔值
let boolean = true; console.log(boolean.toString())
输出:'true'
let boolean = false; console.log(boolean.toString())
输出:'false'
Function.prototype.toString()
console.log(Function.toString())
输出: function Function() { [native code] }
// 函数表达式
function hello(){
console.log('hello lindadayo')
}
console.log(hello.toString())
输出:
function hello(){
console.log('hello lindadayo')
}
// 函数声明式
const hello = () => {
console.log('hello lindadayo')
}
console.log(hello.toString())
输出:
() => {
console.log('hello lindadayo')
}
Date.prototype.toString()
和valueOf()不一致的是,toString直接转成当前时区的字符表示,而valueOf转成的是从1970年1月1日0时0分0秒到现在的毫秒时间
let date = new Date(2023, 1, 14); console.log(date.toString())
输出:Tue Feb 14 2023 00:00:00 GMT+0800 (中国标准时间)
Number.prototype.toString()
numObj.toString([radix])radix:指定要用于数字到字符串的转换的基数 (从 2 到 36)。如果未指定
radix
参数,则默认值为 10
const count = 10;
console.log(count.toString()); // 输出 '10'
console.log((17).toString()); // 输出 '17'
console.log((17.2).toString()); // 输出 '17.2'
const x = 6;
console.log(x.toString(2)); // 输出 '110'
console.log((254).toString(16)); // 输出 'fe'
console.log((-10).toString(2)); // 输出 '-1010'
console.log((-0xff).toString(2)); // 输出 '-11111111'
和parseInt不一样的是,parseInt遇到小数点的话,会直接停止,例如 parseInt(1.5),输出为1
5、有趣toString()问题
const a = {
// ???
}
if (a == 1 && a == 2 && a == 3) {
// 询问:对象a里写啥,才能进入这里呢?
}
答案:
const a = {
num: 1,
toString: function() {
return this.num++;
}
}
解析: 因为每次==比较时,都要先将对象a转为数字,首先调用valueOf(),依然是原对象,再调用toString(),如果没有重写toString方法的话,那么转换结果为 '[object Object]',肯定和1不相等,所以重写toString后,每次调用时,依次++,所以才能通过if判断语句(这里为啥不用全等,要用双等号呢?因为全等的话,第一步变量a的类型为Object,肯定不等于Number类型,所以只能用双等号)
6、['1', '2', '3'].map(parseInt)
parseInt(string, radix) 用于将字符串转换为radix 进制数字,第二参数默认不传的话,为10进制
那么题目拓展开来代码为:
['1', '2', '3'].map((item, index) => {
return parseInt(item, index);
});
每次循环结果如下:
parseInt('1', 0) // radix为0时,按照10为基数处理。返回 1
parseInt('2', 1) // radix范围为2-36,所以无法解析,返回NaN
parseInt('3', 2) // radix为2表示的数中,最大值为1,所以无法解析,返回NaN
所以最终结果为:
[1, NaN, 1NaN]
7、function is not defined at HTMLButtonElement.onclick
1、情景描述:
最近林大大在封装新的功能时候,就遇到这问题了,然后到处查,也没有发现有效的解答,示例如下:在html里面,我写了一个类,用es6 module形式引入,然后想绑定外部的div点击事件,就会提示 startRecord is not defined at HTMLButtonElement.onclick,自然而然第一反应肯定就是不在同一个作用域,然后我就想用es6的写法怎么办呢?
2、解决方法
1、通过绑定在window对象上
因为不管啥作用域,都能访问到window对象,所以这么绑定是妥妥可行的
window.startRecord = () => {
lveRecord.startRecord()
}
2、获取dom并且监听点击事件
document.querySelector('xxx').addEventListener('click', () => {})
3、为哈会出现此种情况?
先得从es6 module说起了,他是被浏览器默认支持的,效果等同于defer,也就是异步延迟加载,等页面渲染完毕后再执行,并且只执行一次,所以也就是说页面都已经渲染完了,module里才开始执行,所以就没法获取到此函数,所以好的解决方式就是我上面两种。
---持续更新---