Python测开28期-偕行-JavaScript数据类型

1、基本数据类型:

  • 也叫值类型或原始值,表示在语言最低层面的不可变值。除了 null,所有原始类型都可以使用 typeof 获取其类型。typeof null 返回 “object”,因此必须使用 === null 来测试 null。

  • 除了 null 和 undefined,所有原始类型都有它们相应的对象包装类型,这为处理原始值提供可用的方法;当在原始值上访问属性时,JavaScript 会自动将值包装到相应的包装对象中,并访问对象上的属性。然而,在 null 或 undefined 上访问属性时,会抛出 TypeError 异常,这需要采用可选链运算符。

  • 基本数据类型存储在栈内存中,占用的内存较小,可以直接操作它们的值,而且是按值传递的,即一个变量的值是直接存储在变量中的,它们的比较也是按值进行的。

    • null:空,特指对象的值未设置,在布尔运算中被认为是falsy。
    • undefined:未定义。
    • String:字符串;
    • number:数值,包含NaN;
    • boolean:布尔类型;
    • symbol:ES6 引入了一种新的原始数据类型,表示独一无二的值。
    • BigInt :大整数,能够表示超过 Number 类型大小限制的整数,ES 2020新增。
      image

2、引用数据类型:

  • 引用类型的对象存储于堆内存中,占用的内存较大,不能直接操作它们的值,而是需要通过引用(内存地址)来访问它们的属性和方法,它们的赋值和比较也是按引用(内存地址)进行的,即一个变量的值是一个指向实际对象的引用(内存地址)。

    • Object:对象;
    • array:数组;
    • function:函数:
    • RegExp:正则;
    • Date:日期;

3、基本数据类型与引用数据类型区别

由于基本类型和引用类型的差异,它们在使用上也有所不同。

  • 当我们对基本类型进行赋值、传参和比较时,只是对它们的值进行操作,而不会影响其他变量的值。

  • 但是对于引用类型,如果我们将一个引用类型变量赋值给另一个变量,那么两个变量实际上是指向同一个对象的引用。这意味着,如果我们在其中一个变量上进行修改,另一个变量也会受到影响。

(1)基本类型和引用类型在参数传递中的区别

<script>
    // 定义数值型变量a
    let a = 10;
    // 定义object型变量obj
    let obj = { value: 20 };
    // 定义一个方法
    function change(x, y) {
        console.log("x=",x);// 输出x=10
        x = 20;
        console.log("x=",x);// 输出x=20
        console.log("a=",a);// 输出a=10
        y.value = 30;
    }
    // 调用方法
    change(a, obj);
    console.log(a); // 输出 10
    console.log(obj.value); // 输出 30
</script>

解析:

  • 基本类型的参数传递是值传递,函数内部对参数的修改不会影响原变量的值;

  • 引用类型的参数传递是引用传递,函数内部对参数的修改会影响原变量的值,因为函数内部修改的是参数指向的对象的属性值。

(2)基本类型和引用类型在赋值中的区别

<script>
    // 定义a并赋值
    let a = 10;
    console.log("a=",a) //a= 10
    // 定义b,并把a的值赋值给b
    let b = a;
    console.log("b=",b)//b= 10
    // 给变量a重新赋值
    a = 20;
    console.log("a=",a)//a= 20
    console.log("b=",b)// b= 10

    // 定义对象obj1
    let obj1 = { value: 10 };
    // 定义对象obj2,并把obj1赋值给obj2
    let obj2 = obj1;
    console.log("obj2=",obj2);//obj2= {value: 10}
    // 将obj1的值修改为20
    obj1.value = 20;
    console.log("obj2=",obj2);//obj2= {value: 20}
</script>

解析:

  • 基本类型的赋值是将变量的值复制一份给新变量,修改其中一个变量的值不会影响另一个变量的值。

  • 引用类型的赋值是将变量的指针(内存地址)复制一份给新变量,两个变量指向同一个对象,修改其中一个变量指向的对象的属性值会影响另一个变量指向的对象。

(3)基本类型和引用类型的相等比较

<script>
    // 定义a并赋值
    let a = 10;
    // 定义b,并把a的值赋值给b
    let b = "10";
    console.log(a == b)// true
    console.log(a === b)//false

    // 定义对象obj1
    let obj1 = { value: 10 };
    // 定义对象obj2,并把obj1赋值给obj2
    let obj2 = obj1;
    console.log(obj1 == obj2);//true
    console.log(obj1 === obj2);//true

    // 定义两个object对象
    let obj3 = { value: 10 };
    let obj4 = { value: 10 };
    console.log(obj3 == obj4)//false
    console.log(obj3 === obj4)//false
</script>

解析:

  • 基本类型的相等比较是值比较,只有两个变量的值完全相同才相等。

  • 引用类型的相等比较是指针(内存地址)比较,只有两个变量指向同一个对象才相等。

A、== 和 !==

  • ==表示先转换类型(自动)再比较值。如果两个值相等,肯定相等,如果两个值不等,也可能是相等的,按以下情况进行判断:–-==表示值相等

    • 1、如果一个是null、一个是undefined,那么相等。
    • 2、如果一个是字符串,一个是数值,把字符串转换成数值再进行比较。
    • 3、如果任一值是 true,把它转换成 1 再比较;如果任一值是 false,把它转换成 0 再比较。
    • 4、如果一个是对象,另一个是数值或字符串,把对象转换成基础类型的值再比较。
  • 注意:对象转换成基础类型,利用它的toString或者valueOf方法。js核心内置类,会尝试valueOf先于toString;例外的是Date,Date利用的是toString转换。非js核心的对象。

例子:表达式"1" == true;返回结果为true。

解析: true转成1,再把“1”转成1,进行比较。(“==”会在两个值数据类型不同时,自动转化为同类型进行值比较);

  • !===的逆反,在不等式两端数据类型不同时,自动转化成相同的数据类型,在进行值比较,如果值相同则返回结果为false,否则为true。–-!=表示值不等

B、=== 和 !===

  • === 先判断数据类型,(类型不同时,不会自动转换类型)如果不是同一类型直接为false。如果类型相同,再判断其值,如果值也相同则返回true,否则返回false。===表示的是绝对的相等

    • 1、如果被比较的两个值数据类型不相等则不等。
    • 2、如果被比较的两个值都是数值,并且是同一个值,判定相等。
    • 3、如果被比较的两个值都是字符串,每个位置的字符都一样,那么相等;否则不相等。
    • 4、如果被比较的两个值都是布尔类型的true,或者都是false,那么相等。
    • 5、如果被比较的两个值都引用同一个对象或函数,那么相等;否则不相等。
    • 6、如果两个值都是null,或者都是undefined,那么相等。

例子:

假设给定 x=5;
表达式① x===5 返回结果为 true;
表达式② x===“5” 返回结果为 false。

解析:针对给定表达式x=5知,将数值5赋值给变量x,即:变量x为数值类型变量。因此,对于表达式①,等号两端数据类型均为数值类型,类型相同,再比较数值,均为5,因此值与类型均相同,所以返回结果为true。而对于表达式②来说,等号坐标变量x数据类型为数值型,等号右端变量数据类型为字符串类型,二者数据类型不相同,由于“===”表达式不能实现自动转换数据类型,因此返回数据结果为false。

  • !=== 用来判断两个值是否不全等,和不等类似,不同的是它不会做自动的类型转换,值是什么类型就是什么类型,如果两个值的类型不同,直接返回true。—!===表示全不等,类型和值都不等

(4)基本类型和引用类型的类型判断

  • typeof:js中关键字,用于获取值的类型;
  • instanceof :类型判断运算符,如果两边的类型一致返回true,否则返回false;
<script>
    console.log(typeof 10); // 输出 "number"
    console.log(typeof {}); // 输出 "object"

    let obj = { value: 10 };
    console.log(typeof obj) // 输出 "object"
    console.log(obj instanceof Object); // 输出 true
</script>

4、动态和弱类型

JavaScript 是一种动态类型语言。JavaScript 中的变量与任何特定值类型没有任何关联,任何变量都可以被赋予或重新赋予各种类型的值:

let foo = 42; // foo 现在是一个数值
foo = "bar"; // foo 现在是一个字符串
foo = true; // foo 现在是一个布尔值

JavaScript 也是一个弱类型语言,这意味着当操作涉及不匹配的类型时,它允许隐式类型转换,而不是抛出类型错误。

const foo = 42; // foo 现在是一个数值
    const result = foo + "1"; // JavaScript 将 foo 强制转换为字符串,因此可以将其与另一个操作数连接起来
    console.log(result); // 421

注意: 隐式强制转换是非常方便的,但当转换发生在预期之外的地方,或发生在预期的另一个方向(例如,字符串转换为数值,而不是数值转换为字符串)时,就会产生一些微妙的错误。对于 symbol 和 BigInt,JavaScript 有意禁止了某些隐式类型转换。

5、null类型和undefined类型

  • Null 类型只有一个值:null。
  • Undefined 类型只有一个值:undefined。
  • null 是一个关键字,但是 undefined 是一个普通的标识符,恰好是一个全局属性。在实践中,这两个差异很小,因为 undefined 不应该被重新定义或者遮蔽。

从概念上讲,undefined 表示 的缺失,null 表示对象 的缺失(这也可以说明 typeof null === "object" 返回true的原因)。当某些东西没有值时,该语言通常默认为 undefined

  • 没有值return;return语句,隐式返回 undefined
  • 访问不存在的对象属性obj.iDontExist),返回 undefined
  • 变量声明时没有初始化let x;),隐式初始化为 undefined
  • 许多像 Array.prototype.find()和 Map.prototype.get() 的方法,当没有找到元素时,返回 undefined

6、Number类型

Number 类型包括整数和浮点数值。也支持不同进制的表示方式。

基本的数值字面量格式是十进制整数,十进制整数可以像下面这样直接在代码中输入:

<script>
    let a = 666;
    console.log(typeof a);// number
</script>

(1)浮点数值

  • 浮点数的数值中必须包含一个小数点,并且小数点后面必须至少有一位数字。如果小数点后面没有数字,或者本身表示的就是有一个整数(例如1.0),那么该值会被转换为整数保存。
<script>
    let floatNum1 = 1.1; 
    console.log(floatNum1)// 1.1
    console.log(typeof floatNum1)// number

    let floatNum2 = 1.; // 小数点后面没有数字——解析为 1 
    console.log(floatNum2)// 1
    console.log(typeof floatNum2)// number

    let floatNum3 = .1; // 有效,但不推荐
    console.log(floatNum3)// 0.1
    console.log(typeof floatNum3)// number

    let floatNum4 = 10.0; // 整数——解析为 10 
    console.log(floatNum4)// 10
    console.log(typeof floatNum4)// number
</script>
  • 对于那些极大或极小的数值,可以用e表示法(即科学计数法)来表示。e后面的数字代表10的幂中的指数,该幂值用来与前面的数相乘;
<script>
    let floatNum1 = 6.123e7; 
    console.log(floatNum1)// 61230000
    console.log(typeof floatNum1)// number
</script>
  • 浮点数值的最高精度是17位小数,但是进行算数运算时是有误差的;
<script>
    let a = 0.1;
    let b = 0.2;
    console.log(a + b);// 0.30000000000000004
</script>

因此,应该要避免以下例子的测试:

if (a + b == 0.3) { 
	// ...do something
}

最可靠的是使用 toFixed() 方法对计算结果进行四舍五入:

<script>
    console.log(0.1+0.2)// 0.30000000000000004
    console.log((0.1 + 0.2).toFixed(1)); // 0.3

    console.log((0.28 * 100 + 0.14 * 100) / 100)// 0.4200000000000001
    console.log(((0.28 * 100 + 0.14 * 100) / 100).toFixed(2)); // 0.42

    // 要注意的是 toFixed() 方法返回的是字符串,如果是将计算结果展示到页面上是很方便的。
    // 如果是需要数值的情况,还要进行类型转换操作,例如使用"+"将其转换为数值:
    console.log(typeof (0.1 + 0.2).toFixed(1)) // string
    console.log(typeof +(0.1 + 0.2).toFixed(1)) // number
</script>

(2)数值范围

由于内存限制,JavaScript不能保存所有的数值。如果某次计算的结果得到了一个超出 JavaScript数值范围的值,那么这个数值将被自动转换成特殊的 Infinity 值。具体来说,如果这个数值是负数,则会被转换成 -Infinity(负无穷) ,如果这个数值是正数,则会被转 换成 Infinity(正无穷)

(4)NaN

NaN,即非数值(Not a Number),这是一个特殊的数值,当算术运算的结果不表示数值时,通常会遇到它,它也是 JavaScript 中唯一不等于自身的值。拥有以下两个特点:

  • 任何涉及 NaN 的操作(例如 NaN/10)都会返回 NaN。

  • NaN 与任何值都不相等,包括 NaN 本身。

    • 鉴于NaN不等于自身,可以使用 isNaN() 全局函数来判断一个值是否是 NaN 值。该函数会对传入的参数尝试转换为数值(如果参数类型不是number的话),例如字符串“1”或者布尔值。任何不能被转换为数值的值都会导致该函数返回true
<script>
    console.log(isNaN(NaN));         // true 
    console.log(isNaN(10));          // false(10是一个数值) 
    console.log(isNaN("10"));        // false(可以被转换成数值 10) 
    console.log(isNaN("blue"));      // true(不能转换成数值) 
    console.log(isNaN(true));        // false(可以被转换成数值 1)
    console.log(isNaN("true"));      // true(不能转换成数值)
</script>

(5)数值转换

有 3个函数可以把其他类型的值转换为数值,转成功就得到响应的数值,转失败就得到NaN:

  • Number():把任何数据类型的值转换为数值;

  • parseInt():把字符串转换为整数值;

  • parseFloat():把字符串转换为浮点数值;

<script>
    let a = "10.11"
    //  Number():把任何数据类型的值转换为数值;
    console.log(Number(a))            // 10.11
    console.log(typeof Number(a))     // number

    // parseInt():把字符串转换为整数值;
    console.log(parseInt(a))          // 10
    console.log(typeof parseInt(a))   //number

    // parseFloat():把字符串转换为浮点数值;
    console.log(parseFloat(a))        // 10.11
    console.log(typeof parseFloat(a)) //number

    // 转失败就得到NaN
    let b = "hello"
    console.log(Number(b))            // NaN
    console.log(typeof Number(b))     // number

    console.log(parseInt(b))          // NaN
    console.log(typeof parseInt(b))   //number

    console.log(parseFloat(b))        // NaN
    console.log(typeof parseFloat(b)) //number
</script>

7、String类型

字符串可以用双引号( " )、单引号( ’ )或反引号(`)标识。以下三种形式都是合法的:

<script>
    let name1 = "小明";
    let name2 = '小明';
    let name3 = `小明`;

    console.log(typeof name1) // string
    console.log(typeof name2) // string
    console.log(typeof name3) // string
</script>

(1) 字符字面量

String 类型包含一些特殊的字符字面量,也叫转义序列用于表示非打印字符,或者具有其 他用途的字符。这些字符字面量可以出现在字符串中的任意位置,而且也将被作为一个字符来解析。

(2) 转换为字符串

  • toString():这是一个方法,数值、布尔值、对象和字符串值都有toString()方法。

  • String():这是一个全局函数,适用于所有数据类型

(3) 模板字符串

  • 模板字符串相当于加强版的字符串,可以定义多行字符串。还可以利用 ${} 在字符串中插入变量和表达式

  • 特别注意: 模板字符串只能使用 **反引号``**进行定义。

<script>
    // 定义多行字符串
    let s1 = `hello
    world!`;
    console.log(s1); 
    
    // 使用${}插入变量
    let myName = '小明';
    let s2 = `我叫${myName}`;
    console.log(s2); // "我叫小明"

    // 使用${}插入表达式
    let s3 = `我今年${2020-2010}岁`;
    console.log(s3); // "我今年10岁"

    // 使用非``定义字符串--使用' '
    let s4 = '我今年${2020-2010}岁';
    console.log(s4); // "我今年${2020-2010}岁"

    // 使用非``定义字符串--使用" "
    let s5 = "我今年${2020-2010}岁";
    console.log(s5); // "我今年${2020-2010}岁"
</script>

image

(4)String类型特点

  • 字符串是有序的: 字符串中的每个元素在字符串中占据一个位置。第一个元素的索引为 0 ,下一个是索引 1 ,依此类推;

  • 字符串的长度是它的元素的数量;

  • vaScript 字符串是不可变的。这意味着一旦字符串被创建,就不可能修改它。字符串方法基于当前字符串的内容创建一个新的字符串——例如:

    • 使用 `substring()获取原始的子字符串。
    • 使用串联运算符(+)或 `concat()将两个字符串串联。

(5)字符串操作

image
image

8、 Boolean类型

Boolean 类型只有两个字面值:true 和 false。这两个值与数字值不是一回事,因此 true 不一定等于 1,而 false 也不一定等于 0。

(1) 布尔值转换

其他 ECMAScript 类型的值都有与布尔值等价的形式。可以调用 Boolean() 函数来将其他类型转换为布尔值。不同类型转换为布尔值的规则如下表:

9、 BigInt 类型

  • [BigInt类型在 Javascript 中是一个数字的原始值,它可以表示任意大小的整数。使用 BigInt,你可以安全地存储和操作巨大的整数,甚至超过 Number 的安全整数限(Number.MAX_SAFE_INTEGER)—正无穷大。

  • BigInt 是通过将 n 附加到整数末尾或调用 BigInt() 函数来创建的。

<script>
    // BigInt
    const x = BigInt(Number.MAX_SAFE_INTEGER); // 9007199254740991n
    console.log(x + 1n === x + 2n); // false,因为 9007199254740992n 和 9007199254740993n 不相等

    // Number
    console.log(Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2); // true,因为都等于 9007199254740992
</script>

10、 Symbol 类型

  • Symbo唯一 并且不可变 的原始值并且可以用来作为对象属性的键,保证不会与其他代码中的键产生冲突。

11、 Object 类型

JavaScript中的object类型可以简单理解为JSON数据格式或者Python中的字典;

  • JavaScript 中的对象(Object)类型是一组由键、值组成的无序集合,定义对象类型需要使用花括号{ } ,语法格式如下:
{name1: value1, name2: value2, name3: value3, ..., nameN: valueN}

其中 name1、name2、name3、…、nameN 为对象中的键,value1、value2、value3、…、valueN 为对应的值。

  • 在 JavaScript 中, 键要么是字符串类型,要么是 symbol类型。属性值可以是任何类型的值,包括其他对象,从而可以构建复杂的数据结构。

  • 可以通过 对象名.键 来获取或者修改对应键的值;

  • 键值对中的值可以是匿名函数,可以使用对象名.键()执行匿名函数;

<script>
    // 定义一个对象
    var person = {
        name: 'Bob',
        age: 20,
        tags: ['js', 'web', 'mobile'],
        other:{
            city: 'Beijing',
            hasCar: true,
            zipcode: null
        }
    };
    // 查看对象
    console.log(person)
    // 获取对象某个值
    // console.log(person.get(name)) // Uncaught TypeError: person.get is not a function
    console.log(person.age)
    // 新增一个属性
    person.gender = "男"
    console.log(person.gender)
    // 修改属性
    person.name = "Tom"
    console.log(person)
</script>

image

  • 对象应该是可迭代的,详情请看for循环;

12、array类型

数组(Array)是一组按顺序排列的数据的集合,数组中的每个值都称为元素,而且数组中可以包含任意类型的数据。

(1)数组的创建

A、 使用方括号[ ] ,数组中的每个元素使用逗号进行分隔

<script>
    // 定义一个数组
    var arr1 = [1, 2, 3, 'hello', true, null]
    console.log(arr1)
    // 查看类型
    console.log(typeof arr1) // object
    // 获取数组长度
    console.log(arr1.length) // 6
    // 通过下标获取数组元素
    console.log(arr1[3]) // hello
</script>

image

B、使用 Array() 函数来创建数组

<script>
    // 定义一个数组
    var arr1 = new Array(1, 2, 3, 4);
    console.log(arr1);       
    // 查看类型
    console.log(typeof arr1) // object
    // 获取数组长度
    console.log(arr1.length) // 4
    // 通过下标获取数组元素
    console.log(arr1[3]) // 4
</script>

image

(2)数组的特点

  • 异构性:数组中的每个元素可以是任意类型
  • 可变性:数组的长度是可变的,更加类似于Python里的List列表;
  • 有序性:数字的每个元素对应一个下标,从0开始;

(3)数组常用方法

方法 描述
concat() 连接两个或更多的数组,并返回结果。
join() 把数组的所有元素放入一个字符串。元素通过指定的分隔符进行分隔。
reverse() 颠倒数组中元素的顺序。

  • 数组.splice():
    • 删除:(start,num),从下标start开始,删除num个;
    • 插入:(start,num,ele1,ele2),从下标start开始,插入num个ele1,ele2
    • 替换:(start,num,ele1,ele2),从下标start开始,替换num个ele1,ele2

(4)二维数组

	var citys = new Array(3);
    citys[0] = ["深圳", "广州", "东莞", "惠州"];
    citys[1] = ["武汉", "黄冈", "黄石", "鄂州", "荆州"];
    citys[2] = ["济南", "青岛", "烟台", "淄博", "聊城"];

    var citys02 = [
        ["深圳", "广州", "东莞", "惠州"],
        ["武汉", "黄冈", "黄石", "鄂州", "荆州"],
        ["济南", "青岛", "烟台", "淄博", "聊城"]
    ];
    for (var i = 0; i < citys02.length; i++) {
        var cityArray = citys02[i];
        
        console.log(cityArray);

        for(var j = 0;j<=cityArray.length;j++){
            console.log(cityArray[j]);
        }
    }

13、Data日期类型

(1) 创建日期对象

  • 创建当前日期:var date = new Date()

  • 创建指定日期:var date = new Date(年, 月, 日)

  • 创建指定日期时间:var date = new Date(年, 月, 日, 时, 分, 秒)

  • 注意:月从0开始,0表示1月

(2)日期常用方法

方法 描述
Date() 返回当日的日期和时间。
getDate() 从 Date 对象返回一个月中的某一天 (1 ~ 31)。
getDay() 从 Date 对象返回一周中的某一天 (0 ~ 6)。
getMonth() 从 Date 对象返回月份 (0 ~ 11)。
getFullYear() 从 Date 对象以四位数字返回年份。
getHours() 返回 Date 对象的小时 (0 ~ 23)。
getMinutes() 返回 Date 对象的分钟 (0 ~ 59)。
getSeconds() 返回 Date 对象的秒数 (0 ~ 59)。
getMilliseconds() 返回 Date 对象的毫秒(0 ~ 999)。
getTime() 返回 1970 年 1 月 1 日至今的毫秒数(时间戳)。
parse() 返回1970年1月1日午夜到指定日期(字符串)的毫秒数。
setDate() 设置 Date 对象中月的某一天 (1 ~ 31)。
setMonth() 设置 Date 对象中月份 (0 ~ 11)。
setFullYear() 设置 Date 对象中的年份(四位数字)。
setYear() 请使用 setFullYear() 方法代替。
setHours() 设置 Date 对象中的小时 (0 ~ 23)。
setMinutes() 设置 Date 对象中的分钟 (0 ~ 59)。
setSeconds() 设置 Date 对象中的秒钟 (0 ~ 59)。
setMilliseconds() 设置 Date 对象中的毫秒 (0 ~ 999)。
setTime() 以毫秒设置 Date 对象。
toLocaleString() 根据本地时间格式,把 Date 对象转换为字符串。

14、 Function 类型

  • 函数(Function)是一段具有特定功能的代码块,函数并不会自动运行,需要通过函数名调用才能运行;
<script>
    // 定义一个函数
    function sayHello(name){
        return "hello " + name;
    }
    // 调用函数并赋值给一个变量
    var result = sayHello("Tom");
    // 打印变量
    console.log(result)// hello Tom
</script>
  • 函数名可以存储在变量、对象、数组中,而且函数还可以作为参数传递给其它函数也可以作为函数返回值
<script>
    // 定义一个函数A
    function sayHello(name){
        return "hello " + name;
    }
    
    // 定义一个函数B,把函数A作为参数传递给B,B返回函数A的引用
    function displayGreeting(sayFunction){
        return sayFunction;
    }

    // 调用函数B,拿到函数A的引用
    var say = displayGreeting(sayHello);
    // 通过函数引用执行函数A
    var result = say("Tom")
    // 查看结果
    console.log(result) // hello Tom
</script>