《你不知道的JavaScript》是一个不错的JavaScript系列书,书名可能有些标题党的意思,但实符其名,很多地方会让你有耳目一新的感觉。

1.typeof null === "object"// true

ES6中JavaScript的类型有:null、undefined、string、number、boolean、object和symbol。但为啥上面的表达式为true呢?这其实是JavaScript的一个bug。最初设计是根据类型对应的前三位是不是0来判断是否为一个object。而null全部为0,所以null的类型误判为object。要准确判断null需要这样:

var a = null;
(!a && typeof a === "object"); // true

因为null本身是一个假值("",undefined,false,0)。而像function,{},Array等都属于object。

2.undefined与未申明

而对于未赋值的变量,type of 返回undefined,未申明的变量也返回undefined,虽然这有点迷惑,但用以检测一个变量会比较安全:

直接操作一个未申明的变量会报错,所以下面这样检测比较好:

if(typeof a !=="undefined"){}

等同于:

if(window.a){}

通过window的全局属性去检测,看起来更简洁,但是要注意场景,前提是存在window,且a为全局变量。

3.数字的语法

1)JavaScript中数字前面的0可以省略,小数后面的0也可以省略

且toFixed方法本身带有四舍五入的效果。

实际上可能不会有人这么写,直接对一个数字进行小数处理。但让我们认识到,对于数字而言,‘.’被视为常量12的一部分,所以上面的错误就相当于没有属性访问运算符'.'来调用toFixed方法。

以上三种是可以的,以区分'.'是属性访问器还是常量的一部分。

2)最小数

这个错误大家应该都知道,JavaScript中的浮点数并不是十分精确。所以0.1+0.2的结果并非刚好等于0.3。再比如我的ofo账单中

所以在JavaScript中判断浮点数需要带上一个精度范围。

if (!Number.EPSILON) {
Number.EPSILON = Math.pow(2,-52);
};
function numbersCloseEnoughToEqual(n1,n2) {
return Math.abs( n1 - n2 ) < Number.EPSILON;
}
numbersCloseEnoughToEqual(0.1+0.2,0.3) //true

3)最大数

我们对一个字符串进行转换,parseFloat和parseInt都只能到16位。其他的后面全部补0了。这个要注意了,让前端传给的id啊,唯一号啊都应该是字符串的,当然这在调用api的时候没有问题,因为都是字符串。但有一次我遇到这个坑是因为ProtoBuf的自定义协议中别人定义了个19位的int。结果就拿不到数据了。

4.void 运算符

void不改变表达式的结果,只让表达式不返回值。我们可以使用void 0来获得undefined。void 1、void true和undefined之间并没有实质的区别。

其实每个表达式都有返回值,我们在console中操作的时候就会发现。第三个undefined是void的作用。 像赋值表达式,定义表达式的返回值无法运用。

特殊一点的比如setTimeout这个方法,每次调用都会返回一个数字,这个数字其实是计数器的一个唯一标识符,用来让你取消的。你可以用 void抹掉,但这简直是给自己挖坑。

5.不是数字的数字

NaN是个很奇葩的对象,自己不等于自己。

typeof NaN==='number'//true

但它确实属于number。

虽然window自带isNaN方法,但这个方法有bug。居然判断字符也返回true。但可以用到它的奇葩特性来判断NaN。它是唯一一个自己不等于自己的值。

if (!Number.isNaN) {
Number.isNaN = function(n) {
return n !== n;
};
} Number.isNaN(b)

6.奇特的~运算符

位操作符(|和~)和某些特殊数字一起使用时会产生类似强类型转换的效果,返回另外一个数字。

0|undefined//
0|NaN//
0|Infinity //

你可能想到了用来代替parseInt。but,只有10位。

超过11位成了有符号的整数。用乘法相当于parsInt,16位是正确的。超过了就说不好了。

~ 非操作符,在JavaScript中的效果就是值的负数减一。

这个特性可以配合indexOf一起使用:

var a = "Hello World";
if (~a.indexOf( "lo" )) { // true
// 找到匹配!
}
if (!~a.indexOf( "ol" )) { // true
// 没有找到匹配!
}
if (a.indexOf( "lo" ) >= 0) { // true
// 找到匹配!
}
if (a.indexOf( "lo" ) != -1) { // true
// 找到匹配!
}
if (a.indexOf( "ol" ) < 0) { // true
// 没有找到匹配!
}
if (a.indexOf( "ol" ) == -1) { // true
// 没有找到匹配!
}

上面两种比起下面的4种要简洁一些。当然你可能一开始不习惯,这到底是匹配了还是没匹配。记住-1取反为0,0为false。

7.假值的相等比较

==会进行隐式的强制类型转换

"0" == null; // false
"0" == undefined; // false
"0" == false; // true -- 晕!
"0" == NaN; // false
"0" == 0; // true
"0" == ""; // false
false == null; // false
false == undefined; // false
false == NaN; // false
false == 0; // true -- 晕!
false == ""; // true -- 晕!
false == []; // true -- 晕!
false == {}; // false
"" == null; // false
"" == undefined; // false
"" == NaN; // false
"" == 0; // true -- 晕!
"" == []; // true -- 晕!
"" == {}; // false
0 == null; // false
0 == undefined; // false
0 == NaN; // false
0 == []; // true -- 晕!
0 == {}; // false

这个结果真让人大跌眼镜。{}和[]其实是为真的。

更夸张的是:

所以 false==[] 很让人迷惑,背后是因为都转成了0==0。所以最好是使用===来避免不经意的强制类型转换。

8.运算符优先级

&&与||是比较熟悉的。a&&b,如果a为真,则返回b。a||b,如果a为真返回a,否则返回b。

&&可以用来代替单个if。

a&&foo();

如果a为真就执行foo(),如果要执行多个语句,可以用括号括起来,中间用逗号分开。||可以用来处理默认值。

function foo(a){
a=a||1;
//....
}

&& 运算符的优先级高于 || ,而 || 的优先级又高于 ? : 。

a && b || c ? c || b ? a : c && b : a

相当于:

(a && b || c) ? (c || b) ? a : (c && b) : a

小结:以上是《中》的第一部分笔记。

【读书笔记】-- 你不知道的JavaScript的更多相关文章

  1. 读书笔记-你不知道的JavaScript(上)

    本文首发在我的个人博客:http://muyunyun.cn/ <你不知道的JavaScript>系列丛书给出了很多颠覆以往对JavaScript认知的点, 读完上卷,受益匪浅,于是对其精 ...

  2. 【 js 基础 】【读书笔记】Javascript “继承”

    是时候写一写 “继承”了,为什么加引号,因为当你阅读完这篇文章,你会知道,说是 继承 其实是不准确的. 一.类1.传统的面向类的语言中的类:类/继承 描述了一种代码的组织结构形式.举个例子:“汽车”可 ...

  3. 【读书笔记】-- JavaScript模块

    在JavaScript编程中我们用的很多的一个场景就是写模块.可以看成一个简单的封装或者是一个类库的开始,有哪些形式呢,先来一个简单的模块. 简单模块 var foo = (function() { ...

  4. 读书笔记-你不知道的JS中-promise

    之前的笔记没保存没掉了,好气,重新写! 填坑-- 现在与将来 在单个JS文件中,程序由许多块组成,这些块有的现在执行,有的将来执行,最常见的块单位是函数. 程序中'将来'执行的部分并不一定在'现在'运 ...

  5. 读书笔记:JavaScript DOM 编程艺术(第二版)

    读完还是能学到很多的基础知识,这里记录下,方便回顾与及时查阅. 内容也有自己的一些补充. JavaScript DOM 编程艺术(第二版) 1.JavaScript简史 JavaScript由Nets ...

  6. 【读书笔记】-- JavaScript数组

    数组是一段线性分配的内存,它通过整数计算偏移并访问其中的元素.大多数的语言都会要求一个数组的元素是相同类型,但JavaScript数组可以包含任意类型. var misc = ['string', n ...

  7. 【读书笔记】javascript 继承

    在JavaScript中继承不像C#那么直接,C#中子类继承父类之后马上获得了父类的属性和方法,但JavaScript需要分步进行. 让Brid 继承 Animal,并扩展自己fly的方法. func ...

  8. 读书笔记:javascript高级技巧(二)

    四.惰性载入函数 因为浏览器兼容的原因,我们的javascript代码会有大量的if语句,将执行引导到正确的代码中,看如下函数: function createXHR(){ if (typeof XM ...

  9. 读书笔记:javascript高级技巧(一)

    一.安全的类型检测 javascript内置的类型检测机制并非完全可靠,由于浏览器或者作用域等原因,经常会发生错误.大家知道,在任何值调用toString()方法都会返回一个[object Nativ ...

  10. 读书笔记之 - javascript 设计模式 - 接口、封装和链式调用

    javascript 采用设计模式主要有下面的三方面原因: 可维护性:设计模式有助于降低模块之间的耦合程度.这使代码进行重构和换用不同的模块变得容易,也使程序员在大型项目中合作变得容易. 沟通:设计模 ...

随机推荐

  1. 自己开发轻量级ORM(一)

    在开发ORM之前,先简单的介绍下ORM的基本概念. 对象关系映射(Object Relational Mapping,简称ORM)是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术. 简单的 ...

  2. matlab中同一文件定义子函数的方法

    在matlab中一个.m文件中可以有多个的子函数,但仅能有一个主函数,并且M文件名必须和主函数相同在一个m文件中通常有两种定义子函数的方法: 1.嵌套定义 myfunc1会和主函数共享变量名.这种情况 ...

  3. 无需Get更多技能,快速打造一个可持久化的任务调度

    项目总是很忙,忙里偷闲还是要总结一下,前一段时间,由于项目中需要,我们需要很多定时汇总数据的情况,项目初期主要使用sql server 计划任务实现对数据的汇总与统计,但是开发到一定时间内,需求提出了 ...

  4. Docker存储驱动之AUFS简介

    简介 AUFS是曾是Docker默认的首选存储驱动.它非常稳定.有很多真实场景的部署.很强的社区支持.它有以下主要优点: 极短的容器启动时间. 有效的存储利用率. 有效的内存利用率. 虽然如此,但由于 ...

  5. SQLHELPER 帮助类

    using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threa ...

  6. UE4从零搭建CF游戏关卡(蓝图篇)

    一 往关卡中放置物体 二 Static Mesh 和 BSP 从今天开始我们要建立一个类似CF游戏的场景,不写一句代码,纯蓝图实现. 三 英语学习 今天早上开会,经理说了一件让我震惊的事情,她说最近大 ...

  7. 【Zookeeper】源码分析之网络通信(三)

    一.前言 前面已经学习了NIOServerCnxn,接着继续学习NettyServerCnxn. 二.NettyServerCnxn源码分析 2.1 类的继承关系 public class Netty ...

  8. 上传图片,多图上传,预览功能,js原生无依赖

    最近很好奇前端的文件上传功能,因为公司要求做一个支持图片预览的图片上传插件,所以自己搜了很多相关的插件,虽然功能很多,但有些地方不能根据公司的想法去修改,而且需要依赖jQuery或Bootstrap库 ...

  9. querySelectorAll与getElementsBy对比有什么不同

    querySelectorAll与getElementsBy对比有什么不同javascript中的querySelectorAll与getElementsBy都可以获取dom元素对象,但是他们又有什么 ...

  10. for循环的表达规则,for循环的嵌套,跳转语句;穷举;迭代;异常处理

    for循环的基本格式 for(表达式1:表达式2:表达式3) { 循环体: } for循环的四要素 表达式1就是变量初始化:表达式2就是循环条件:表达式3是状态改变 static void Main( ...