【你不知道的javaScript 中卷 笔记1】javaScript中的类型与值
一、类型与值
1.0 javaScript 七种内置类型:
- 空值(null)
- 未定义(undefined)
- 布尔值( boolean)
- 数字(number)
- 字符串(string)
- 对象(object)
- 符号(symbol,ES6 中新增)
1.1 typeof 运算符查看值的类型
typeof
对null
的处理显示“object”,并非显示“null”,typeof null === "object"; // true
这是javaScript
语言的一个bug
,需要使用复合条件来检测 null
值的类型
var a = null;
(!a && typeof a === "object"); // true
function
不是 JavaScript
的一个内置类型,它是 object
的一个“子类型”,但是typeof
处理函数显示"function"
typeof function a(){ /* .. */ } === "function"; // true
对于数组类型,也是 object 的一个“子类型”typeof [1,2,3] === "object"; // true
1.2 undefined 和 undeclared
var a;
typeof a; // "undefined"
typeof b; // "undefined"
b 是 一个undeclared变量,但typeof b并没有报错,因为typeof有一个特殊的安全防范机制。利用typeof的安全防范机制,可以安全的判断,即使变量不存在也不会报错阻断程序如:
// 如果DEBUG不存在js引擎就会报错
if (DEBUG) {
console.log( "Debugging is starting" );
}
// 这样是安全的
if (typeof DEBUG !== "undefined") {
console.log( "Debugging is starting" );
}
1.3 数组
在 JavaScript 中,数组可以容纳任何类型的值,可以是字符串、 数字、对象(object),甚至是其他数组
var a = [ 1, "2", [3] ];
a.length; // 3
a[0] === 1; // true
a[2][0] === 3; // true
数组声明后即可向其中加入值,不需要预先设定大小
var a = [ ];
a.length; // 0
a[0] = 1;
a[1] = "2";
a[2] = [ 3 ];
a.length; // 3
含有空白或空缺单元的数组,可以正常运行
var a = [ ];
a[0] = 1;
// 此处没有设置a[1]单元
a[2] = [ 3 ];
a[1]; // undefined
a.length; // 3
可以包含字符串键值和属性,但这些并不计算在数组长度内
var a = [ ];
a[0] = 1;
a["foobar"] = 2;
a.length; // 1
a["foobar"]; // 2
a.foobar; // 2
如果字符串键值能够被强制类型转换为十进制数字的话,就会被当作数字索引来处理。
var a = [ ];
a["13"] = 42;
a.length; // 14
类数组转换成数组,ES5中可以通过数组的工具函数如Array.prototype.slice.call()
ES6工具函数 Array.from(..)
1.4 字符串
字符串和数组很类似,有length 属性以及 indexOf(..)和 concat(..) 方法,但javaScript 中字符串是不可变的,字符串的成员函数不会改变其原始值,而是创建并返回一个新的字符串。可以通过“借用”数组的非变更方法来处理字符串:
var a = "foo"
var c = Array.prototype.join.call(a,"-")
var d = Array.prototype.map.call(a,(v)=>{
return v.toUpperCase() + '.'
}).join("")
join
数组原型对象上的方法,可以将数组转换成字符串,
var a = "foo"
Array.prototype.reverse.call(a)
console.log(a)
在字符串上使用数组的反转函数会报错,因为字符串一旦初始化就不会改变TypeError: Cannot assign to read only property '0' of object '[object String]'
1.5 数字
tofixed(..)
方法可指定小数部分的显示位数
var a = 42.59;
a.toFixed( 0 ); // "43"
a.toFixed( 1 ); // "42.6"
a.toFixed( 2 ); // "42.59"
a.toFixed( 3 ); // "42.590"
a.toFixed( 4 ); // "42.5900"
toPrecision(..)
方法用来指定有效数位的显示位数:
var a = 42.59;
a.toPrecision(1 ); // "4e+1"
a.toPrecision( 2 ); // "43"
a.toPrecision( 3 ); // "42.6"
上面的方法不仅适用于数字变量,也适用于数字常量
// 无效语法,. 被视为常量 42. 的一部分
42.toFixed( 3 ); // SyntaxError
// 下面的语法都有效:
(42).toFixed( 3 ); // "42.000"
0.42.toFixed( 3 ); // "0.420"
42..toFixed( 3 ); // "42.000"
//42..tofixed(3) 则没有问题,因为第一个 . 被视为 number 的一部分,第二个 . 是属性访问 运算符
42 .toFixed(3); // "42.000"
从 ES6 开始,严格模式(strict mode)不再支持 0363 八进制格式(新格式如 下)。0363 格式在非严格模式(non-strict mode)中仍然受支持
ES6 支持以下新格式:
0o363; // 243的八进制
0O363; // 同上
0b11110011; // 243的二进制
0B11110011; // 同上
0.1 + 0.2 === 0.3; // false
二进制浮点数中的 0.1 和 0.2 并不是十分精确,它们相加的结果并非刚好等于 0.3,而是一个比较接近的数字 0.30000000000000004,所以条件判断结果为 false。
怎样来判断 0.1 + 0.2 和 0.3 是否相等呢?
设置一个误差范围值,通常称为“机器精度”(machine epsilon),对javaScript
的数字来说,这个值通常是 2^-52 (2.220446049250313e-16)
。
从 ES6 开始,该值定义在 Number.EPSILON
中
if (!Number.EPSILON) {
Number.EPSILON = Math.pow(2,-52);
}
使用 Number.EPSILON 来比较两个数字是否相等
function numbersCloseEnoughToEqual(n1,n2) {
return Math.abs( n1 - n2 ) < Number.EPSILON;
}
var a = 0.1 + 0.2;
var b = 0.3;
numbersCloseEnoughToEqual( a, b ); numbersCloseEnoughToEqual( 0.0000001, 0.0000002 ); // false
Number. MAX_VALUE
:最大浮点数大约是 1.798e+308
Number.MIN_VALUE
:最小浮点数大约是 5e-324,无限接近于 0
整数的安全范围
ES6: Number.MAX_SAFE_INTEGER:
“安全”呈现的最大整数是2^53 - 1,即9007199254740991
ES6: Number. MIN_SAFE_INTEGER
:最 小 整 数 是 -9007199254740991
由于 JavaScript 的数字类型无法精确呈现 64 位数值,所以必须将它们保存(转换)为字符串
整数检测
ES6 中的 Number.isInteger(..)
:检测一个值是否是整数
polyfill Number.isInteger(..) 方法
if (!Number.isInteger) {
Number.isInteger = function(num) {
return typeof num == "number" && num % 1 == 0;
};
}
ES6 中的 Number.isSafeInteger(..) 方法:检测一个值是否是安全的整数
polyfill Number.isSafeInteger(..) 方法:
if (!Number.isSafeInteger) {
Number.isSafeInteger = function(num) {
return Number.isInteger( num ) &&
Math.abs( num ) <= Number.MAX_SAFE_INTEGER;
};
}
32 位有符号整数
a | 0可以将变量a中的数值转换为32位有符号整数,因为数位运算符|只适用于32位 整数,因此与 0 进行操作即可截取 a 中 的 32 位数位。
1.6 特殊数值
undefined
- 指从未赋值
- 是一个标识符,可以被当作变量来使用和赋值
- void 运算符,undefined 是一个内置标识符(除非被重新定义,见前面的介绍),它的值为 undefined, 通过 void 运算符即可得到该值。
var a = 42;
console.log( void a, a ); // undefined 42
//void并不改变表达式的结果, 只是让表达式不返回值:
null
- null 指空值(empty value)
- 曾赋过值,但是目前没有值
- null 是一个特殊关键字,不是标识符
NaN
- 不是数字的数字
- 是一个“警戒值”(sentinel value,有特殊用途的常规值),用于指出数字类型中的错误 情况,即“执行数学运算没有成功,这是失败后返回的结果”。
- NaN是一个特殊值,它和自身不相等,是唯一一个非自反
var a = 2 / "foo";
var b = "foo";
a; // NaN b; "foo"
window.isNaN( a ); // true
window.isNaN( b );// true
isNaN(..) 检查参数是否不是 NaN,也不是数字,"foo" 不是一个数字,但是它也不是 NaN
ES6工具函数 Number.isNaN(..)
if (!Number.isNaN) {
Number.isNaN = function(n) {
return (
typeof n === "number" && window.isNaN( n )
}
var a = 2 / "foo"
var b ="foo"
); };
Number.isNaN( a ); // true
Number.isNaN( b );// false
Infinity
var a = 1 / 0; // Infinity
var b = -1 / 0; // -Infinity
零值
为什么会有 -0 ?
有些应用程序中的数据需要以级数形式来表示(比如动画帧的移动速度),数字的符号位 (sign)用来代表其他信息(比如移动的方向)。此时如果一个值为 0 的变量失去了它的符号位,它的方向信息就会丢失。所以保留 0 值的符号位可以防止这类情况发生。
区分 -0 和 0方法:
function isNegZero(n) {
n = Number( n );
return (n === 0) && (1 / n === -Infinity);
}
isNegZero( -0 ); // true
isNegZero( 0 / -3 ); // true
isNegZero( 0 );// false
特殊等式
Es6工具方法 Object.is(..)
var a = 2 / "foo";
var b = -3 * 0;
Object.is( a, NaN );
Object.is( b, -0 );
Object.is( b, 0 );
if (!Object.is) {
Object.is = function(v1, v2) {
// 判断是否是-0
if (v1 === 0 && v2 === 0) {
return 1 / v1 === 1 / v2;
}
// 判断是否是NaN
if (v1 !== v1) {
return v2 !== v2;
}
// 其他情况
return v1 === v2;
};
}
1.7 值和引用
var a = 2;
var b = a; // b是a的值的一个副本
b++;
a; // 2
b; // 3
var c = [1,2,3];
var d = c; // d是[1,2,3]的一个引用
d.push( 4 );
c; // [1,2,3,4]
d; // [1,2,3,4]
简单值(即标量基本类型值,scalar primitive)总是通过值复制的方式来赋值 / 传递,包括 null、undefined、字符串、数字、布尔和 ES6 中的 symbol。
复合值(compound value)——对象和函数,则总 是通过引用复制的方式来赋值 / 传递。
引用指向的是值本身而非变量,所以一个引用无法更改另一个引用的指向
var a = [1,2,3];
var b = a;
a; // [1,2,3]
b; // [1,2,3]
// 然后
b = [4,5,6];
a; // [1,2,3]
b; // [4,5,6]
b=[4,5,6] 并不影响 a 指向值 [1,2,3],除非 b 不是指向数组的引用,而是指向 a 的指针,在 javaScript 中不存在指针
function foo(x) {
x.push( 4 );
x; // [1,2,3,4]
// 然后
x = [4,5,6];
x.push( 7 );
x; // [4,5,6,7]
}
var a = [1,2,3];
foo( a );
a; // 是[1,2,3,4],不是[4,5,6,7]
向函数传递 a 的时候,实际是将引用 a 的一个复本赋值给 x,而 a 仍然指向 [1,2,3]。 在函数中我们可以通过引用x来更改数组的值(push(4)之后变为[1,2,3,4])。但x = [4,5,6] 并不影响 a 的指向,所以 a 仍然指向 [1,2,3,4]。不能通过引用 x 来更改引用 a 的指向,只能更改 a 和 x 共同指向的值。
foo( a.slice() );
slice(..) 不带参数会返回当前数组的一个浅复本(shallow copy)。由于传递给函数的是指向该复本的引用,所以 foo(..) 中的操作不会影响 a 指向的数组。
如果要将标量基本类型值传递到函数内并进行更改,就需要将该值封装到一个复合值(对象、数组等)中,然后通过引用复制的方式传递。
function foo(wrapper) {
wrapper.a = 42;
}
var obj = {
a: 2
};
foo( obj );
obj.a; // 42
总结
- 赋值 / 参数传递是通过引用复制还是值复制完全由值的类型来决定,所以使用哪种类型也间接决定了赋值 / 参数传递的方式。
- null 类型只有一个值 null,undefined 类型也只有一个值 undefined。所有变量在赋值之 前默认值都是 undefined。void 运算符返回 undefined。
- 数字类型有几个特殊值,包括 NaN(意指“not a number”,更确切地说是“invalid number”)、+Infinity、-Infinity 和 -0。
【你不知道的javaScript 中卷 笔记1】javaScript中的类型与值的更多相关文章
- JavaScript进阶内容笔记1:各种对象类型判断
该文章主要用来介绍JavaScript中常用的一些对象检测判断方法,整理资源来自书本和网络,如有错误或说明不详之处,望评论提出,本菜定提名感谢……(本文章知识比较基础,大牛请提些意见再绕道,三克油^_ ...
- 【你不知道的javaScript 中卷 笔记2】javaScript中的类型转换
1.1 对象内部属性 [[Class]] 常见的原生函数: String() Number() Boolean() Array() Object() Function() RegExp() Date( ...
- 《高性能JavaScript》学习笔记——日更中
------------------2016-7-20更------------------ 最近在看<高性能JavaScript>一书,里面当中,有讲很多提高js性能的书,正在看的过程中 ...
- EF中System.Data.Entity.Internal.AppConfig的类型初始值设定项引发异常
使用Entity的时候遇到的一个错 问题出在项目的App.config中 解决: 1.configSections要写在最顶端 2. 当中的incariantName会变成incariantNodeN ...
- 《你不知道的JavaScript(中卷)》读书笔记
中卷有点无聊,不过也是有干货的,但是好像要背一下的样子.不过作者大大都夸我是“优秀的开发人员”了,肯定要看完呀~~ 开发人员觉得它们太晦涩,很难掌握和运用,弊(导致bug)大于利(提高代码可读性).这 ...
- 从头开始学JavaScript 笔记(一)——基础中的基础
原文:从头开始学JavaScript 笔记(一)--基础中的基础 概要:javascript的组成. 各个组成部分的作用 . 一.javascript的组成 javascript ECMASc ...
- 《编写可维护的javascript》读书笔记(中)——编程实践
上篇读书笔记系列之:<编写可维护的javascript>读书笔记(上) 上篇说的是编程风格,记录的都是最重要的点,不讲废话,写的比较简洁,而本篇将加入一些实例,因为那样比较容易说明问题. ...
- 学习笔记:JavaScript传参方式———ECMAScript中所有函数的参数都是按值传递
我们把命名参数(arguments)视为局部变量,在向参数传递基本类型值时,如同基本类型变量的复制一样,传递一个副本,参数在函数内部的改变不会影响外部的基本类型值.如: function add10( ...
- 编程笔记:JavaScript 中的类型检查
在Badoo的时候我们写了大量的JS脚本,光是在我们的移动web客户端上面就有大概60000行,可想而知,维护这么多JS可是相当具有挑战性的.在写如上规模js脚本客户端应用的时候我们必须对一件事保持警 ...
随机推荐
- Metasploit学习笔记(一) Samba服务 usermap_script安全漏洞相关信息
一.Samba介绍 Samba是linux和unix系统上实现smb协议的一个免费软件,由客户机和服务器构成.SMB是一种在局域网上实现共享文件和打印机的协议.存在一个服务器,客户机通过该协议可以服务 ...
- Android 7.0新特性“Nougat”(牛轧糖)。
1.Unicode 9支持和全新的emoji表情符号 Android Nougat将会支持Unicode 9,并且会新增大约70种emoji表情符号.这些表情符号大多数都是人形的,并且提供不同的肤色, ...
- [RHEL8]关闭SELinux(同CentOS7)
修改配置文件(永久修改) # vi /etc/selinux/config SELINUX=disabled # 关闭 SELINUX=enforcing # 开启 命令方式(临时修改重启失效) # ...
- 杭电-------2055An Easy Problem(C语言)
#include<stdio.h> int main() { int m; int i; scanf("%d", &m); ]; int y; int z; ; ...
- 1Python学习CentOS 7 Linux环境搭建
鉴于python3目前已成流行之势,而各发行版Linux依然是自带python2.x,笔者尝试在centos7下,部署Python3.x与2.x共存环境 本文参考博主良哥95网址https://blo ...
- C++ Primer抄书笔记(二)——变量和基本类型(下)
四.const限定符[引用/指针/顶层/常量表达式] const对象值不变,必须初始化,能完成此type的大部分operation. 一般,多文件独立变量,编译初始化仅文件内有效: 除非,(条件:初值 ...
- 正则表达式验证IP地址(绝对正确)
正则验证合法_有效的IP地址(ipv4/ipv6) 不墨迹直接上代码: 正则表达式: /^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[ ...
- fancybox图片灯箱功能
fancybox图片灯箱功能 在页面中引入几个文件 <script src="https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery ...
- 【读书笔记】https://source.android.google.cn/devices/bootloader
https://source.android.google.cn/devices/bootloader 本文主要记录aosp官网关于bootloader的相关资料 Bootloader A bootl ...
- spark 报错 InvalidClassException: no valid constructor
2019-03-19 02:50:24 WARN TaskSetManager:66 - Lost task 1.0 in stage 0.0 (TID 1, 1.2.3.4, executor 1) ...