《你不知道的JavaScript》整理(五)——值与原生函数

简介: JavaScript只有一种数值类型:number(数字),包括“整数”和带小数的十进制数。

一、值


1)数字

JavaScript只有一种数值类型:number(数字),包括“整数”和带小数的十进制数。


//数字的语法
var a = 5E10; // 50000000000
a.toExponential();  // "5e+10"
var b = a * a;  // 2.5e+21 
var c = 1 / a; // 2e-11
var d = 0.42;
var e = .42; //数字前面的0可以省略
var f = 42.; //小数点后小数部分最后面的0也可以省略


由于数字值可以使用Number对象进行封装,因此数字值可以调用Number.prototype中的方法。例如,tofixed(..)方法可指定小数部分的显示位数:


// 无效语法:
42.toFixed( 3 );    // SyntaxError
// 下面的语法都有效:
a = (42).toFixed(3); // "42.000" 
b = 0.42.toFixed(3); // "0.420" 
c = 42..toFixed(3); // "42.000"
d = 42 .toFixed(3); // "42.000"


2)整数检测


//整数检测
if (!Number.isInteger) {
  Number.isInteger = function(num) {
    return typeof num == "number" && num % 1 == 0;
  };
}
//安全整数检测
if (!Number.isSafeInteger) {
  Number.isSafeInteger = function(num) {
    return Number.isInteger(num) &&
      Math.abs(num) <= Number.MAX_SAFE_INTEGER;
  };
}


3)null与undefined

特殊数值undefined与null。它们的名称既是类型也是值。

null指空值(empty value),曾赋过值,但是目前没有值。null是一个特殊关键字,不是标识符,我们不能将其当作变量来使用和赋值。

undefined指没有值(missing value),从未赋值。undefined是一个标识符,可以被当作变量来使用和赋值。


//将undefined当作变量来使用和赋值
function foo() {
  "use strict";
  var undefined = 2;
  console.log(undefined); // 2
}
foo();


4)不是数字的数字

NaN意指“不是一个数字”(not a number),将它理解为“无效数值”、“失败数值”或者“坏数值”可能更准确些。

NaN是一个特殊值,它和自身不相等,是唯一一个非自反(自反,即x === x不成立)的值。而NaN != NaN为true。


var a = 2 / "foo"; // NaN
typeof a === "number"; // true
if (!Number.isNaN) {
  Number.isNaN = function(n) { //非数字类型的值在isNaN中也会返回true
    return (
      typeof n === "number" &&
      window.isNaN(n)
    );
  };
}
//利用NaN不等于自身这个特点
if (!Number.isNaN) {
  Number.isNaN = function(n) {
    return n !== n;
  };
}


5)零值

加法和减法运算不会得到负零(negative zero)。负零在开发调试控制台中通常显示为“-0”,但在一些老版本的浏览器中仍然会显示为“0”。


//零值
a = 0 / -3; // -0
b = 0 * -3; // -0
c = +"-0"; // -0
d = Number("-0"); // -0
e = JSON.parse("-0"); // -0
//值比较
-0 == 0; // true
-0 === 0; // true
0 > -0; // false
//-0的判断方式
function isNegZero(n) {
  n = Number(n);
  return (n === 0) && (1 / n === -Infinity);
}
isNegZero(-0); // true
isNegZero(0 / -3); // true
isNegZero(0); // false


6)特殊等式

NaN和-0在相等比较时的表现有些特别。

由于NaN和自身不相等,所以必须使用ES6中的Number.isNaN(..)。 而-0等于0(对于===也是如此),因此我们必须使用isNegZero(..)这样的工具函数。


//特殊等式
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;
  };
}


7)值和引用

JavaScript引用指向的是值。如果一个值有10个引用,这些引用指向的都是同一个值,它们相互之间没有引用/指向关系。

向函数传递值的时候,实际是将引用值的一个复本传递进去,不管是基本类型还是对象。


//基本类型
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]
//变量引用不同的值
var a = [1, 2, 3];
var b = a;
b = [4, 5, 6]; //给b重新赋值,引用新的值,不影响a的引用
a; // [1,2,3]
b; // [4,5,6]
//函数内让参数重新引用值
function foo2(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];
//向函数传递a的时候,实际是将引用a的一个复本赋值给x,而a仍然指向[1,2,3]
foo2(a);
a; // 是[1,2,3,4],不是[4,5,6,7]


上面的源码可以在此次浏览

 

二、原生函数


常用的原生函数有:String()、Number()、Boolean()、Array()、Object()、Function()、RegExp()、Date()、Error()、Symbol()。

1)内部属性[[Class]]

这个属性无法直接访问,一般通过Object.prototype.toString(..)来查看。


//内部属性[[Class]]
Object.prototype.toString.call([1, 2, 3]); // "[object Array]" 
Object.prototype.toString.call(/regex-literal/i); // "[object RegExp]"
//基本类型
Object.prototype.toString.call(null); // "[object Null]"
Object.prototype.toString.call(undefined); // "[object Undefined]"


虽然Null()和Undefined()这样的原生构造函数并不存在,但是内部[[Class]]属性值仍然是"Null"和"Undefined"。

基本类型值被各自的封装对象自动包装,所以它们的内部[[Class]]属性值分别为"String"、"Number"和"Boolean"。


Object.prototype.toString.call("abc"); // "[object String]"
Object.prototype.toString.call(42); // "[object Number]"
Object.prototype.toString.call(true); // "[object Boolean]"


2)封装对象包装

由于基本类型值没有.length和.toString()这样的属性和方法,需要通过封装对象才能访问,此时JavaScript会自动为基本类型值包装(box或者wrap)一个封装对象:


//封装对象
var a = "abc";
a.length; // 3
a.toUpperCase(); // "ABC"

如果想要自行封装基本类型值,可以使用 Object(..) 函数(不带 new 关键字)


//自行封装基本类型
var a = "abc";
var b = new String(a);
var c = Object(a);
typeof a; // "string" 
typeof b; // "object" 
typeof c; // "object"
b instanceof String; // true 
c instanceof String; // true
Object.prototype.toString.call(b); // "[object String]" 
Object.prototype.toString.call( c ); // "[object String]"


3)拆封

如果想要得到封装对象中的基本类型值,可以使用valueOf()函数:


//拆封
var a = new String("abc");
var b = new Number(42);
var c = new Boolean(true);
console.log(a.valueOf()); // "abc"
console.log(b.valueOf()); // 42
console.log(c.valueOf()); // true


在需要用到封装对象中的基本类型值的地方会发生隐式拆封。

上面的源码可以在此处浏览

相关文章
|
6天前
|
JavaScript 前端开发 Java
[JS]同事:这次就算了,下班回去赶紧补补内置函数,再犯肯定被主管骂
本文介绍了JavaScript中常用的函数和方法,包括通用函数、Global对象函数以及数组相关函数。详细列出了每个函数的参数、返回值及使用说明,并提供了示例代码。文章强调了函数的学习应结合源码和实践,适合JavaScript初学者和进阶开发者参考。
15 2
[JS]同事:这次就算了,下班回去赶紧补补内置函数,再犯肯定被主管骂
|
5天前
|
前端开发 JavaScript 开发者
除了 Generator 函数,还有哪些 JavaScript 异步编程解决方案?
【10月更文挑战第30天】开发者可以根据具体的项目情况选择合适的方式来处理异步操作,以实现高效、可读和易于维护的代码。
|
4天前
|
移动开发 前端开发 JavaScript
前端实训,刚入门,我用原生技术(H5、C3、JS、JQ)手写【网易游戏】页面特效
于辰在大学期间带领团队参考网易游戏官网的部分游戏页面,开发了一系列前端实训作品。项目包括首页、2021校园招聘页面和明日之后游戏页面,涉及多种特效实现,如动态图片切换和人物聚合效果。作品源码已上传至CSDN,视频效果可在CSDN预览。
前端实训,刚入门,我用原生技术(H5、C3、JS、JQ)手写【网易游戏】页面特效
|
19天前
|
JavaScript 前端开发
JavaScript 函数语法
JavaScript 函数是使用 `function` 关键词定义的代码块,可在调用时执行特定任务。函数可以无参或带参,参数用于传递值并在函数内部使用。函数调用可在事件触发时进行,如用户点击按钮。JavaScript 对大小写敏感,函数名和关键词必须严格匹配。示例中展示了如何通过不同参数调用函数以生成不同的输出。
|
21天前
|
存储 JavaScript 前端开发
JS函数提升 变量提升
【10月更文挑战第6天】函数提升和变量提升是 JavaScript 语言的重要特性,但它们也可能带来一些困惑和潜在的问题。通过深入理解和掌握它们的原理和表现,开发者可以更好地编写和维护 JavaScript 代码,避免因不了解这些机制而导致的错误和不一致。同时,不断提高对执行上下文等相关概念的认识,将有助于提升对 JavaScript 语言的整体理解和运用能力。
|
30天前
|
JavaScript 前端开发
js教程——函数
js教程——函数
26 4
|
29天前
|
存储 JavaScript 前端开发
js中函数、方法、对象的区别
js中函数、方法、对象的区别
15 2
|
1月前
|
JavaScript 前端开发 Java
【javaScript数组,函数】的基础知识点
【javaScript数组,函数】的基础知识点
23 5
|
1月前
|
JavaScript 前端开发
Node.js 函数
10月更文挑战第5天
19 3
|
1月前
|
前端开发 JavaScript
探索JavaScript函数基础
探索JavaScript函数基础
17 3