【javascript】《你不知道的javascript》中卷笔记 傷城~ 2022-04-05 06:08 175阅读 0赞 > 7种内建类型 null / undefined / object / number / string / boolean ES6 新增了一个 symbol 类型 > typeof 操作符 (7个值) 返回的也是7个值,typeof 总是会返回字符串: typeof undefined === 'undefined' typeof 42 === 'number' typeof '42' === 'string' typeof { life: 420 } === 'object' typeof true === 'boolean' //ES6 新增的 typeof Symbol() === 'symbol' //但是 typeof null 的结果 是令人吃惊的 typeof null === 'object' 所以我们判断null的时候不能简单的这样判断,需要像下面这样: const a = null const isNull = !a && typeof(a) === 'object' 但是并不如像上面说的那样 typeof 有7个值,只有6个,除了null的都有,我们看下第七个是什么: typeof function test(){ } === 'function' javascript里面,变量没有类型,值才有。 变量在任何时候,持有任何值。 证明typeof返回的是一个字符串, 安全的防范机制,`typeof var` 无论var是否声明都不会报错,阻塞程序 typeof typeof 66 === 'string' 还有一个特殊的情况: `typeof NaN === 'number'` > 数组的小坑 数组也是对象,可以添加属性 const a = [] a[0] = 0 a['name'] = 'arr-name' console.log(a) // [0, name: "arr-name"] console.log(a.length) // 1 a['0'] = 'zero' console.log(a) // ["zero", name: "arr-name"] console.log(a.length) // 1 > 类数组的操作 比如DomList 我们需要对其做一些过滤操作什么的,但是它只是一个类数组【索引为数字,并且可以遍历】 // 在chrome控制台下可以做实验 var tempDomList = document.getElementsByTagName('ul') // 我们是可以tempDomList[0]去获取第一个ul标签元素,但是没法使用数组的方法 我们以前是Array.prototype.METHOD.call(arr, params)… 比如想使用find方法这样使用: const specialUl = Array.prorotyle.find.call( tempDomList, (item)=>{ item.className.includes('special-class') }) 现在可以直接使用 Array.from(类数组对象) Array.from(temp).find((item)=>{ item.className.includes('special-class') }) > 小数的坑 因为0.1 和0.2 js里面,二进制表示也是不精确的,两个错误的值相加,肯定不会等于一个正确的值。 对所有使用IEEE754的语言的,都存在这个问题。 0.1 + 0.2 === 0.3 // false > NaN 注意: NaN === NaN 的结果是false 还有一个方法:`isNaN` isNaN 的本意是判断值是否是 NaN , isNaN(NaN) 的结果是true 但是isNaN(‘foo’) 的结果也是true 这个bug在ES6 用新的方法来解决了: `Number.isNaN` > 装箱 和 java有点类似,基础数据类型和包装类型,比如我们定义一个字符串: `var str = "kevin"` 执行 `str.length()` 实际上js会自动封箱。 但是比如你想自己手动装箱,比如这样 const flag = new Boolean(false) if(!flag) { console.log('come here') //actualy never come here } > 开箱 或者拆箱 比如你有一个包装器对象,想取去底层的基本类型值,你可以使用valueOf方法。valueOf MDN地址在这里: [https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global\_Objects/Object/valueOf][https_developer.mozilla.org_zh-CN_docs_Web_JavaScript_Reference_Global_Objects_Object_valueOf] const a = new String("str") a == "str" // true a ==== "str" // false valueOf 可以构造一个比较奇怪的例子,当然仅限于 `==` 运算符 : const a = { name: "kevin", valueOf: "$2000M" } a == "$2000M" // true a === "$2000M" // false > JSON.stringify 基础类型直接转换为字符串 JSON.stringify(null) // "null" JSON.stringify(true) // "true" JSON.stringify(42) // "42" JSON.stringify("42") // ""42"" 当JSON.stringify()遇到 undefined function()\{\} symbol的时候 会自动忽略他们。 **如果它们出现在对象里面,这些属性会自动的被忽略**,请看例子: const obj = { name: undefined, sayHi: function(){ console.log('hello') }, id: Symbol('Kevin') } console.log(JSON.stringify(obj)) // 输出的结果是 "{}" **如果它们出现在数组里面,这些值会被替换为null,请看例子:**,请看例子: const arr =["kevin", undefined, Symbol("kevin"), function(){ }] console.log(JSON.stringify(arr)) // 输出的结果是 "["kevin",null,null,null]" 有时候我们有这样的需求,需要将转换后的字符串格式化,加上换行/ 或者说只打印出想要的结果,这时候需要加上第二个参数和第三个,这个请直接移步 [MDN-JSON.stringify][] 留意如果转换的目标有toJSON方法,那么这个方法首先会被调用,然后将该方法返回的值,作为序列化的参数。 > 布尔类型 被强制转换为boolean,然后结果是false 只有极少数,他们是 `+0, -0, NaN` `null, undefined` `false` `""` `document.all` //dom对象 参考(MDN-Boolean)\[[https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global\_Objects/Boolean][https_developer.mozilla.org_zh-CN_docs_Web_JavaScript_Reference_Global_Objects_Boolean]\] 强制将其他数据类型转换为布尔类型,可以使用Boolean(xx),但是太繁琐,可以使用!!双否定操作符。 > String <-> Number;String和Number的转换 数字转字符串 const a = 42 const aStr1 = a.toString() const aStr2 = a + '' 字符串到数字 const a = "42" const numberA = + a const b = "42" const numberB = b - 0 // 因为 - 仅为数字减法定义的,所以b - 0 强制b的值转换为数字。 // 当然用 b / 1 或者 b * 1 都是可以的。 > 对数组做一个减法操作 var a = [3] var b = [1] a - b // 结果是 2 两个数组因为 - 减号运算符必须转换为number,但是他们首先会被强制转换为string(使用toString()序列化),然后再强制转换为number。所以最后的结果是2。 转换为字符串的明确转换是这个 `String(youVariable)` 转换为字符串隐式转换是这个 `yourVariable + ""` 按照上面的数组来举例: var a = [3] a.toString() // "3" String(a) // "3" a + "" // "3" -------------------- 这里有分割线,看了上面几个点,你可能以为`String(a)` 和`a + ""` 的结果是一样的,但是实际上内部使不同的。 `a + ""` 现在a值上面调用`valueOf()`方法 然后调用`toString()`方法 `String(a)` 是直接调用的`toString()`方法 证明: const a = { valueOf: function() { return 42 }, toString: function() { return 4 } } a + "" // "42" String(a) // "4" so… but 这里还有一个 [] + { } // "[object Object]" { } + [] // 0 学不动了… 不学了! -------------------- 真香分割线 > 比较:任何值与boolean var a = "42" var b = true a == b // 肯定是false, 是的和你认为的一样 都是false // 但是 a == false // 也是false // 但是 + 1 // 会进入if语句 if(a) { console.log("come here !") } 首先我们来看这个`a==b` 如果typeOf(a)是Boolean,会返回ToNumber(a)==b的结果,对b来说也是这样,所以知道了吧? 然后我们看if语句,实际上if语句里面做了一个隐式转换。 // 隐式转换 if(a) { //... } // 明确转换 * 1 强烈推荐~~~~ if(!!a) { //... } // 明确转换 * 2 if (Boolean(a)) { //... } > 比较:非object 与 object 如果一个 object / function / array 被与一个简单基本标量(string, number, boolean)进行比较。 ES5规范中是这样说的: 如果 Type(x)是一个String 或者Number而 Type(y)是一个Object,返回比较`x == ToPrimitive(y)`的结果。 如果 Type(y)是一个String 或者Number而 Type(x)是一个Object,返回比较`y == ToPrimitive(x)`的结果。 但是我们没有说Boolean的情况,你看我们上一点,已经说了Boolean的情况,这里就不在讨论。 所以就会有下面的结果: var arr = [42] arr == 24 // true var obj = { valueOf: function() { return 42; } } obj == 42 // true 请注意valueOf 和 toString方法。前面我们说了`拆箱`,就是一个基本类型值的object包装器(例如new String(‘abc’)这样的形式)被展开,其底层的基本类型值(‘abc’)被返回。这种行为与 == 算法中的ToPrimitive强制转换有关: var a = "abc" var b = Object(a) a === b // false a == b // true // 这里a == b 是true,是因为b通过ToPrimitive强制转换为 // 它的底层简单基本标量值 "abc", 它与a中的 "abc"是相等的。 这里a == b 是true,是因为b通过ToPrimitive强制转换为 它的底层简单基本标量值 “abc”, 它与a中的 "abc"是相等的。 但是 `==` 也会存在意外的情况,上面说的拆箱情况也有例外。考虑下面的代码: var a = null var b = Object(a) // 与 Object() 相同 a == b // false var c = undefined var d = Object(a) // 与 Object() 相同 c == d // false var e = NaN var f = Object(e) // 与 new Number(e) 相同 e == f // false 重点: 值 null 和 undifiend 不能被装箱,他们没有等价的对象包装器。 所以Object(null), Object(undefined) 和 Object()一样,他们都仅仅产生一个普通对象。 NaN是可以被封箱到它等价的Number对象包装器中,但是拆箱之后NaN==NaN是false。 > 基于valueOf做奇怪的操作 我们已经知道了将一个对象和一个基本数据类型做 `==` 比较,实际上对这个object做了一次拆箱操作,然后再做比较。 所以才会有下面的这些结果: var a = ["42"] a == "42" // true var a = { valueOf: () => "42" } a == "42" // true 因为拆箱动作是调用了一个函数,这个函数我们可以控制,所以我们可以做到怪戾的操作,看下面的代码。 if (a == 2 && a == 3) { console.log("come here") } 实际上是可以进入到if语句内部的,在知道valueOf之前,我是一脸懵逼的,但是我们可以用valueOf来达到这个效果。 var a = { value: 1, // 这里用箭头函数会报错,因为箭头函数内部this,指的是window valueOf: function() { this.value = this.value + 1; return this.value } } if ( a == 2 && a == 3 ) { console.log('yep. come here ') } 还有另外一个例子, 但是请永远不要在业务代码做这些骚操作: Number.prototype.valueOf = function() { return 3; } new Number(2) == 3 // true **一个对象转为原始值,可以调用toString, 也可以调用valueOf方法,valueOf的优先级高于toString()** \*\* 还有一个优先级高于上面两个方法的设定 [Symbol.toPrimitive][]\*\* var a = { toString() { return 12 } } a + 1 ; var a = { toString() { return 12 }, valueOf() { return 13 } } a + 1; -------------------- 分割线,第五章文法的笔记较少,看了表达式的一堆概念性的东西。。 > \{\} + \[\] 和 \{\} + \[\] 的区别 在前面我们说到了这两个表达式的值的结果: { } + [] // 0 [] + { } // "[object Object]" 为什么会有这样的结果。 [点击这个链接][Link 1] > 浏览器环境下个定义一个有合法id的dom元素 我们可以直接通过id,来获取到这个dom元素。 [https_developer.mozilla.org_zh-CN_docs_Web_JavaScript_Reference_Global_Objects_Object_valueOf]: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/valueOf [MDN-JSON.stringify]: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify [https_developer.mozilla.org_zh-CN_docs_Web_JavaScript_Reference_Global_Objects_Boolean]: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Boolean [Symbol.toPrimitive]: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Symbol/toPrimitive [Link 1]: https://blog.csdn.net/a5534789/article/details/86177971
还没有评论,来说两句吧...