JavaScript数据类型和语法

第一章 类型

1.2 内置类型

使用 typeof 检测对象类型并不是非常安全的行为:

// 安全的
typeof undefined    // 'undefined'
typeof true         // 'boolean'
typeof 42           // 'number'
typeof '42'         // 'string'
typeof {}           // 'object'
typeof Symbol()     // 'symbol'
typeof (function(){}) // 'function'
// 不安全的
typeof null         // 'object'
typeof []           // 'object'

函数对象可以拥有属性。函数的length属性为其声明的参数个数。

⚠️

  • null 是基本类型中唯一一个“假值”!!!
  • function(函数)也是JavaScript 的一个内置类型。然而查阅规范就会知道, 它实际上是 object 的一个“子类型”。具体来说,函数是“可调用对象”,它有一个内部属 性 [[Call]],该属性使其可以被调用(函数不仅是对象,还可以拥有属性)

1.3 值和类型

JavaScript 中的变量是没有类型的,只有值才有。变量可以随时持有任何类型的值

1.3.1 undefined和undeclared

声明但还没有赋值的变量是undefined。 还没有在作用域声明过的变量是undeclared(【严格模式】下访问会抛出ReferenceError)。

对于 undeclared(或者 not defined)变量,typeof 照样返回 "undefined",并且不会报错,返回'undefined'。

或者当其为全局变量的时候,用window的点操作符去访问,也不会报错。

第二章 值

2.1 数组

在稀疏数组中,中间未赋值的内容会初始化为undefined

var a = [];
a[0] = 1;
a[2] = 3;

a[1]; // undefined
a.length; // 3

⚠️也可以用键访问(输入不能转换为数字的字符串)去设置数组的属性,但他们不会纳入数组的值和length,而是作为独立的属性存在。

var arr = [];
  arr[0] = 1;
  arr["2"] = 2;
  arr["obb"] = 3;
  arr.length; // 3
  arr[2]; // 2, “2”字符串键值 被强制转换为十进制数字
  arr.obb; arr["obb"]; // 3

类数组(Array Like)(一组通过数字索引的值)

如:DOM查询返回的DOM元素列表;arguments(es6废除)

  • 对象表示其类型类似于数组,但是原型链上没有Array对象,自然也无法直接使用Array的原型方法。
  • 转换类数组使用ES5的Array.prototype.slice.call(arrayLikeObj),slice() 返回参数列表(上例中是一个类数组)的一个数组复本。或者ES6的Array.from(arrayLikeObj)。

    function foo() {
    var arr = Array.prototype.slice.call( arguments );
    或 var arr = Array.from( arguments );
    arr.push( "bam" );
    console.log( arr );
    }
    foo( "bar", "baz" ); // ["bar","baz","bam"]

2.2 字符串

和数组相似,都有 length 属性以及 indexOf(..),和 concat(..) 方法

可以通过“借用”数组的非变更方法来处理字符串:字符串没有join、map方法

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( "" );

JS中字符串的单个字符不可变,不能用键访问去改变字符串的某个字符。 字符串也可以借用数组的一些原型方法来进行处理。一个常用场景是字符串的倒置:

var c = a
        // 先转为Array
        .split('')
        // 再倒置Array
        .reverse()
        // 最后转回字符串
        .join('');

2.3 数字

直接对数字字面量调用原型方法,有时候需要两个点(.),这是因为第一个点会被理解为小数点。 Number.prototype上有这些方法:

  • toExponential(),转为指数格式,特别大或小的数字默认用指数格式显示
  • toFixed(),指定小数位数
  • toPrecision(),指定有效位数的显示位数
    // 无效语法:
    42.toFixed( 3 ); // SyntaxError ,因为 . 被视为常量 42. 的一部分
    // 下面的语法都有效:
    (42).toFixed( 3 ); // "42.000"
    0.42.toFixed( 3 ); // "0.420"
    42..toFixed( 3 ); // "42.000"
    其他进制的问题:
  • 0xf3,16进制
  • 0b11110011,2进制
  • 0o363,8进制

2.3.2 较小的数值

0.1 + 0.2 === 0.3; // false,二进制浮点数中的 0.1 和 0.2 并不是十分精确,相加的结果0.30000000000000004

解决方法:误差范围值,即机器精度(machine epsilon)。 使用机器精度,可以判断两个浮点值的运算结果是否等于另一个数字。Math.abs(n1 - n2) < Number.EPSILON

2.3.3 整数安全范围

安全的最大整数是2^53 - 1,即9007199254740991,ES6中为Number.MAX_SAFE_INTEGER。同理,最小整数为其负数-(2^53 - 1),ES6中为Number.MIN_SAFE_INTEGER。

2.3.4 整数检测

  • Number.isInteger,检测是否为整数
  • Number.isSafeInteger,检测是否为安全的整数

2.3.5 32位有符号整数

数位运算符只适用于32位的整数,其他数位将会被忽略。

2.4 特殊数值

2.4.1 不是值的值

空值:

  • null,指空值,曾经赋值,现在没有值empty value
  • undefined,指没有值,从未被赋值,missing value

null 是一个特殊关键字,不是标识符,我们不能将其当作变量来使用和赋值。然而 undefined 却是一个标识符,可以被当作变量来使用和赋值。

2.4.2 undefined

通过void运算符可以返回undefined。

var a = 42; 
console.log( void a, a ); // undefined 4,void 并不改变表达式的结果, 只是让表达式不返回值:

2.4.3 特殊的数字

  • NaN是一个警戒值,表示数学运算没有成功,失败后返回的结果。
    NaN 是一个特殊值,它和自身不相等,是唯一一个非自反 NaN != NaN 为 true
    ES6 判断是否为NaN:Number.isNaN(a)
  • Infinity表示无穷数,数学运算结果溢出
    var a = 1 / 0; // Infinity
    var b = -1 / 0; // -Infinity

    规范规定,如果数学运算(如加法)的结果超出处理范围,则由 IEEE 754 规范中的“就 近取整”(round-to-nearest)模式来决定最后的结果。
    计算结果一旦溢出为无穷数(infinity)就无法再得到有穷数
  • -0表示第一位正负位为负,保留了该信息,后续处理的时候会携带它。
    对负零进行字符串化会返回 "0"; 如果反过来将其从字符串转换为数字,得到的结果是准确的
    -0 == 0; // true
    -0 === 0; // true

    ⚠️为什么需要负0:保留0的符号位,来获取方向信息。

2.4.4 特殊等式

ES6:Object.is(..):来判断两个值是否绝对相等(用来处理特殊比较,否则使用==或===解)

  • Object.is(NaN, NaN) === true
  • Object.is(+0, -0) === false

2.5 值和引用

简单值(即基本类型值),通过值复制的方式来赋值/传递。 复合值(对象、数组和函数),总是通过引用复制的方式来赋值/传递。 减少引用复制副作用的方法是,传递时候采用复本创建的方式,比如a.slice()。

slice(..) 不带参数会返回当前数组的一个浅复本

⚠️标量基本类型值是不可更改的(字符串和布尔也是如此)。

function foo(x) {    
    x = x + 1;    
    x; // 3  
} 
var a = 2; 
var b = new Number( a ); // Object(a)也一样 
foo( b ); 
console.log( b ); // 是2,不是 3

.......待补充!!

第四章 强制类型转换

4.1 值类型转换

显式值类型转换称为类型转换,发生在静态语言的编译阶段。隐式的情况称为强制类型转换,发生在动态语言的运行时。 JS中只存在强制类型转换(运行时中转换),只会返回标量基本类型值,比如字符串、数字和布尔值,不会返回对象或函数。

4.2 抽象值操作

4.2.1 toString

  • null -> 'null'
  • undefined -> 'undefined'
  • true/false -> 'true'/'false'
  • 极大数,极小数 -> 指数形式表达
  • Array -> arr.join(',')
  • Object -> obj.toPrimitive

对于JSON安全:包含undefined、function、symbol和循环引用的对象不符合JSON的结构标准,它们在stringify操作中会被忽略,数组中转为null。 当一个对象JSON不安全时,可以定义其toJSON()方法来返回一个JSON安全的对象,它在JSON.stringify的时候会隐式调用。 JSON.stringify(target, replacer?, space?)的replacer可以是一个字符串数组或函数,用于指定哪些属性需要纳入处理。space指定缩进格式。

4.2.2 ToNumber

  • true/false -> 1/0
  • undefined -> NaN
  • null -> 0
  • 对象:调用toPrimitive,首先检查该值有没有valueOf()方法,如有则执行,如没有就使用toString()方法,对最终结果进行强制类型转换。如果两者均不返回基本类型值,抛出TypeError错误。

4.2.3 toBoolean

JS中的假值通常为基本类型:

  • undefined
  • null
  • false
  • +0, -0, NaN
  • ''(空字符串)

4.3 显式强制类型转换

4.3.1 字符串和数字之间的显式转换

Number转String:

  • String(a)
  • a.toString()

String转Number:

  • Number(b)
  • Number.parseInt(b) / Number.parseFloat(b)
  • +b:注意不要两个+号连用变成自增,必要时中间加空格。

其他应用:

  • 日期转数字(毫秒级时间戳):var d = new Date(); +d;,但是更建议使用其getTime()方法。
  • ~:JS中的取反操作类似于转换为数字,然后取-(x+1),常用于将-1转为0
  • |:后面跟一个toInt32后为0的值(0,NaN等),可以起到ToNumber的作用。

4.3.2 显式解析数字字符串

Number.parseInt()和Number.parseFloat()方法允许字符串中含有非数字字符,遇到非数字字符就停止解析,返回结果。 对于非字符串,会隐式调用其toString()方法。

// 得到Infinity,解析为'Infinity',第一个字符I的ASCII码为18,所以返回结果是18
// 十进制下返回NaN
Number.parseInt(Infinity, 19);

// toString()解析成了8e-7,返回8
Number.parseInt(0.0000008) 

4.3.3 显式转换为布尔值

Boolean()可以显式转换为布尔值,另一种方法是用!和!!。 if(...) {}的判断语句中,如果没有特别声明布尔值,就会调用toBoolean()方法。

4.4 隐式强制类型转换

4.4.2 字符串和数字之间的隐式强制类型转换

+运算符能用于数字加法,也能用于字符串拼接。它一旦遇到两边有一者不是Number的情况,就会对双方调用toPrimitive()或toString()方法,然后进行字符串拼接。 -运算符仅用于数字减法,一旦遇到两边有一者表示Number的情况,就会对双方调用ToNumber()行为,然后计算减法。

4.4.5 ||和&&

它们的返回值是两个操作数中的一个。

||:

  • 如果前者判断为true,就返回前者,否则返回后者。
  • 类似于a? a:b。
  • 常用作空值合并运算符。

&&:

  • 如果前者判断为true,就返回后者,否则返回前者。
  • 类似于a? b:a。
  • 常用作守护运算符,前面的表达式为后面把关。比如if(a){ foo(); }可以改成a && foo();。

4.4.6 Symbol的强制类型转换

Symbol只支持显式强制类型转换。

var s1 = new Symbol('cool');
String(s1); // 'Symbol(cool)'

s1+ ''; // TypeError

4.5 宽松相等和严格相等

4.5.2 抽象相等

==允许再相等比较中进行强制类型转换,===不允许。 特别注意,以下情况用Object.is()修复:

  1. NaN不等于NaN。
  2. +0等于-0

ES5规范11.9.3.4-5定义:

  1. 如果Type(x)是数字,Type(y)是字符串,则返回 x == ToNumber(y) 的结果。
  2. 如果Type(x)是字符串,Type(y)是数字,则返回 ToNumber(x) == y 的结果。

ES5规范11.9.3.6-7定义:

  1. 如果Type(x)是布尔类型,则返回 ToNumber(x) == y 的结果。
  2. 如果Type(y)是布尔类型,则返回 x == ToNumber(y) 的结果。

可以使用a == null来替代a === undefined || a === null。 ES5规范11.9.3.2-3定义:

  1. 如果x为null,y为undefined,返回true。
  2. 如果x为undefined,y为null,返回true。

ES5规范11.9.3.8-9定义:

  1. 如果Type(x)是字符串或数字,Type(y)是对象,则返回 x == ToPrimitive(y)的结果。
  2. 如果Type(x)是对象,Type(y)是字符串或数字,则返回 ToPrimitive(x) == y的结果。

特殊情况说明:

'0' == false; // true, Number('0') == Number(false)
false == 0;   // true, Number(false) == 0
false == '';  // true, Number(false) == Number('')
false == [];  // true, Number(false) == ToPrimitive([])
'' == 0;      // true, Number('') == 0
'' == [];     // true, Number('') == ToPrimitive([])
0 == [];      // true, 0 == ToPrimitive([])

4.6 抽象关系比较

比较双方首先调用ToPrimitive,如果出现非字符串,就根据ToNumber规则将双方转换为数字来比较。如果比较双方都是字符串,就按字母顺序来逐位比较。 需要注意的是,a <= b在JS中被处理成!(b < a)。

第五章 语法

5.1 语句和表达式

JS中,表达式可以返回一个结果值。

5.1.1 语句的结果值

语句都有一个结果值(undefined也算)。 对于代码块,其结果值就如同一个隐式的返回,即返回最后一个语句的结果值。

5.1.2 表达式的副作用

语句系列逗号运算符:在()中写入多个语句,用逗号','分隔,返回最后一个语句的结果值。 比如b = (a++, a);可以返回a++之后的a。

5.2 运算符优先级

&&高于||。

猜你喜欢

转载自www.cnblogs.com/gaogao999/p/11097512.html
今日推荐