有趣且重要的JS知识合集(1)JS基础常见问题

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.ownKeysObject.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里才开始执行,所以就没法获取到此函数,所以好的解决方式就是我上面两种。

---持续更新---

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值