• JS的类型和值


    1.类型

    ECMAScript语言中所有的值都有一个对应的语言类型。ECMAScript语言类型包括Undefined、Null、Boolean、String、Number和Object。
    对语言引擎和开发人员来说,类型是值的内部特征,它定义了值的行为,以使其区别于其他值。

    内置类型

    JavaScript有七种内置类型:

    • 空值(null)
    • 未定义(undefined)
    • 布尔值(boolean)
    • 数字(number)
    • 字符串(string)
    • 对象(object)
    • 符号(symbol,ES6中新增)

    除了对象之外,其他统称为“基本类型”。

    我们可以用typeof运算符来查看值的类型,它返回的是类型的字符串值。

    typeof undefined === "undefined";//true
    typeof true === "boolean";//true
    typeof 42 === "number";//true
    typeof "42" === "string";//true
    typeof {life:42} === "object";//true
    
    typeof Symbol() === "symbol";//true
    
    //下面是一个bug
    typeof null === "object";//true
    
    typeof function a(){ /*...*/ } === "function";//true
    

    JavaScript中的变量是没有类型的。只有值才有。变量可以随时持有任何类型的值。
    在对变量执行typeof操作时,得到的结果并不是该变量的类型,而是该变量持有的值的类型,因为JavaScript中的变量没有类型。

    var a = 42;
    typeof a;//"number"
    
    a = true;
    typeof a;//"boolean"
    
    //因为typeof 42返回"number"
    typeof typeof 42;//"string"
    

    2.值

    2.1 数组

    在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
    

    使用delete运算符可以将单元从数组中删除,但是要注意,单元删除后,数组的length属性并不会发生变化。

    var a = [];
    
    a[0] = 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
    

    建议使用对象来存放键值/属性值,用数组来存放数字索引值。

    2.2 字符串

    JavaScript中的字符串和字符数组并不是一回事。

    var a = "foo";
    var b = ["f","o","o"];
    
    a.length;//3
    b.length;//3
    
    a.indexOf("o");//1
    b.indexOf("o");//1
    
    a;//"foo"
    b;//["f","o","o"]
    
    a[1] = "0";
    b[1] = "0";
    
    a;//"foo"
    b;//["f","0","o"]
    

    JavaScript中字符串是不可变的,而数组是可变的。
    a[1]在JavaScript中并非总是合法语法,正确的方法应该是a.charAt(1)
    字符串不可变是指字符串的成员函数不会改变其原始值,而是创建并返回一个新的字符串。

    许多数组函数用来处理字符串很方便(字符串没有这些函数)。

    var a = "foo";
    var b = ["f","o","o"];
    
    a.join;//undefined
    a.map;//undefined
    
    var c = Array.prototype.join.call(a,"-");
    var d = Array.prototype.map.call(a,function(v){
    	return v.toUpperCase() + ".";
    }).join("");
    
    c;//"f-o-o"
    d;//"F.O.O."
    

    2.3 数字

    number(数字),包括"整数"和带小数的十进制数。

    数字的语法

    var a = 0.42;
    var b = .42;
    var c = 42.0;
    var d = 42.;
    

    特别大的特别小的数字默认用指数格式显示。

    var a = 5E10;
    a;//50000000000
    a.toExponential();//"5e+10"
    
    var b = a*a;
    b;//2.5e+21
    
    var c = 1/a;
    c;//2e-11
    
    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
    
    a.toPrecision(1);//4e+1
    a.toPrecision(2);//43
    a.toPrecision(3);//42.6
    a.toPrecision(4);//42.59
    

    但是下面的语法是有效的(请注意其中的空格):

    2.4 特殊数值

    undefined类型只有一个值,即undefined。null类型也只有一个值,即null
    null指空值。
    undefined指没有值。
    null是一个特殊关键字,不是标识符,我们不能将其当作变量来使用和赋值。
    undefined是一个标识符,可以被当作变量来使用和赋值。

    我们通过void运算符即可得到undefined这个值。

    var a = 42;
    
    console.log(void a, a);//undefined 42
    

    按惯例我们用void 0来获得undefined。void 0、void 1和undefined之间并没有实质上的区别。

    特殊的数字

    如果数学运算的操作数不是数字类型,就无法返回一个有效的数字,这种情况下返回值为NaN

    var a = 2/"foo";//NaN
    
    typeof a === "number";//true
    

    NaN仍然是数字类型。
    NaN用于指出数字类型中的错误情况,即“执行数学运算没有成功,这是失败后返回的结果”。

    var a = 2/"foo";
    
    a == NaN;//false
    a === NaN;//false
    

    NaN是一个特殊值,它和自身不相等,是唯一一个非自反的值。
    可以使用内建的全局工具函数isNaN(..)来判断一个值是否是NaN。
    NaN是JavaScript中唯一一个不等于自身的值。

    if(!Number.isNaN){
    	Number.isNaN = function(n){
    		return n != n;
    	};
    }
    
    无穷数
    var a = 1/0;//Infinity
    var b = -1/0;//-Infinity
    

    JavaScript的运算结果有可能溢出。
    规范规定,如果数学运算的结果超出处理范围,则由IEEE754规范中的“就近取整”模式来决定最后结果。
    计算结果一旦溢出为无穷数就无法再得到有穷数。换句话说,就是你可以从有穷走向无穷,但无法从无穷回到有穷。
    无穷除以无穷(Infinity/ Infinity)是一个未定义操作,结果为NaN

    零值
    var a = 0/-3;//-0
    var b = 0*-3;//-0
    

    加法和减法运算不会得到负零。
    根据规范,对负零进行字符串化会返回"0":

    var a = 0/-3;
    a.toString();//"0"
    a + "";//"0"
    String(a);//"0"
    JSON.stringify(a);//"0"
    +"-0";//-0
    Number("-0");//-0
    JSON.parse("-0");//-0
    
    var a = 0;
    var b = 0/-3;
    
    a == b;//true
    -0 == 0;//true
    a === b;//true
    -0 === 0;//true
    
    //区分-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);//true
    Object.is(b,-0);//true
    
    Object.is(b,0);//false
    

    能使用=====时就尽量不要使用Object.is(..),因为前者效率更高,更为通用。Object.is(..)主要用来处理那些特殊的相等比较。

    2.5 值和引用

    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]的一个引用
    c;//[1,2,3,4]
    d;//[1,2,3,4]
    

    简单值总是通过值复制的方式来赋值/传递,包括null、undefined、字符串、数字、布尔和ES6中的symbol。
    复合值——对象(包括数组和封装对象)和函数,则总是通过引用复制的方式来赋值/传递。

    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]
    
    //由于引用指向的是值本身而非变量,所以一个引用无法更改另一个引用的指向。
    
    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]
    
    //我们不能通过引用x来更改引用a的指向,只能更改a和x共同指向的值。
    
    function foo(x){
    	x.push(4);
    	x;//[1,2,3,4]
    	
    	x.length = 0;
    	x.push(4,5,6,7);
    	x;//[4,5,6,7]
    }
    
    var a = [1,2,3];
    
    foo(a);
    a;//[4,5,6,7]
    
    /*
    function foo(wrapper){
    	wrapper.a = 42;
    }
    
    var obj = {
    	a : 2
    };
    
    foo(obj);
    obj.a;//42
    */
    
    /*
    function foo(x){
    	x = x + 1;
    	x;//3
    }
    
    var a = 2;
    var b = new Number(a);//Object(a)也一样
    
    foo(b);
    console.log(b);//2
    */
    

    我们无法自行决定使用值复制还是引用复制,一切由值的类型来决定。

    参考资料:《你不知道的JavaScript》(中卷) 第一部分 前两章

  • 相关阅读:
    iOS-数据存储的常用方式
    Bullet 学习笔记之 Bullet User Manual
    Bullet 学习笔记之 Bullet User Manual
    Bullet 学习笔记之 Bullet User Manual
    Bullet 学习笔记之 CollisionShape 和 CollisionObject
    Bullet Basic Example 示例
    Bullet 学习笔记
    Gazebo 机器人仿真流程之 World 类(二)
    Gazebo 机器人仿真流程之 WorldPrivate 类
    Gazebo 机器人仿真流程之 World 类
  • 原文地址:https://www.cnblogs.com/gzhjj/p/9020330.html
Copyright © 2020-2023  润新知