JavaScript 查缺补漏

\color{red}{本文并不是详细的 JavaScript 介绍,只是整理了一些自己以前忽略了的知识点以及一些自己的理解。}

Round 1 数据类型相关

数据类型

JavaScript 的数据类型共有六种(ES6 又新增了第七种 Symbol 类型的值):
数值(number)、字符串(string)、布尔值(boolean)、undefinednull、对象(object)。
对象又可以分为三个子类:狭义的对象(object)、数组(array)、函数(function)。
其中数值、字符串、布尔值、undefinednull,合称为基本数据类型;而对象称为引用数据类型。

什么是基本数据类型?什么是引用数据类型?

在理解“什么是什么是基本数据类型,什么是引用数据类型”之前,我们先要知道什么是堆内存和栈内存。

栈内存

栈内存主要用于简单存储,一般存储一些大小已知或者有上限的变量。栈内存一般为有序存储,容量小,系统分配效率高。

堆内存

堆内存主要用于存储一些大小未知变量。堆内存存储时不仅要在堆内存中分配存储区域,还要把引用地址存到栈内存中,效率相对较低。

基本数据类型

基本数据是存在栈内存中的简单数据段,可以直接按值访问。
举个栗子:

var a = 1;
var b = a;
b = 2;
console.log(a);  //1
  1. 声明一个变量 a = 1; 此时 a 被存的栈内存中;
  2. 声明一个变量 b = a; 此时 b 获得了 a 值的拷贝,这个时候虽然两个变量的值相等,但是实际上两个变量是保存了两个不同的基本数据类型;
  3. 改变变量 b = 2; 此时 b 变量发生改变但是不会影响变量 a
引用数据类型

引用数据是存在堆内存中的对象,需要通过指向储存对象的内存地址的指针进行访问。

举个栗子:

var obj1 = new Object();
var obj2 = obj1;
obj2.attr= "添加属性";
console.log(obj1.attr); // 添加属性
  1. 声明一个对象 obj1 = new Object(); 此时 obj1 被存的栈内存中,而 obj1 所对应的值是存在堆内存中的对象的一个引用地址(指针);
  2. 声明一个对象 obj2 = obj1; 此时 obj2 获得了 obj1 值的拷贝,此时 obj2 就获得了存在堆内存中的对象的引用地址(指针),这样他们共同指向了同一个堆内存中的对象;
  3. 给对象添加属性 obj2.attr= "添加属性"; 此时 obj2 实际上是为堆内存中的对象添加属性,所以 obj1 同样受到影响;

数据类型确定方法

使用 typeof 确定数据类型(typeof xxx

数值 —— number
字符串 —— string
布尔值 —— boolean
函数 —— function
undefined —— undefined
[], {}, [...], {...}, null —— object

使用 instanceof 确定数据类型(object instanceof constructor
使用 Object.prototype.toString 确定数据类型

null 和 undefined

null:空值
undefined:未定义
undefined == null —— true
Number(null) —— 0
Number(undefined) —— NaN

数值

JavaScript 内部,所有数字都是以64位浮点数形式储存(1 === 1.0 —— true)。

0.1 + 0.2 —— 0.30000000000000004
0.1 + 0.2 === 0.3 —— false

国际标准 IEEE 754,JavaScript 浮点数的 64 个二进制位

  • 符号位(第1位):决定正负(0 —— 正数,1 —— 负数)
  • 指数部分(第2位到第12位):决定大小 —— 64 位浮点数的指数部分的长度是11个二进制位,意味着指数部分的最大值是 2047(2的11次方减1)。也就是说,64 位浮点数的指数部分的值最大为 2047,分出一半表示负数,则 JavaScript 能够表示的数值范围为 210242-1023,超出这个范围的数无法表示(正向溢出:返回 Infinity;负向溢出:返回 0)。
Number.MAX_VALUE // 1.7976931348623157e+308
Number.MIN_VALUE // 5e-324
  • 小数部分(第13位到第64位):决定精度 —— 精度最多只能到53个二进制位,所以,绝对值小于2的53次方的整数,即 -253253 可以精确表示。
数值表示
  • 自动将数值转为科学计数法的几种情况:
    1. 小数点前的数字多于21位;
    2. 小数点后的零多于5个
  • 进制表示:
    1. 十进制:没有前缀;
    2. 二进制:前缀 0b0B
    3. 八进制:前缀 0o0O(或者有前导0、且只用到0-7的数值);
    4. 十六进制:前缀 0x0X

特殊数值
  1. +0 / -0:除了 (1 / +0) === (1 / -0) // false,正零和负零是等价的;
  2. NaNNaN 不等于任何值,包括它本身;
  3. InfinityInfinityNaN 比较,总是返回 false
数值相关操作
  • parseInt() : 将字符串转为整数
    \color{#FF8247}{注:自动转为科学计数法的数字,parseInt会将科学计数法的表示方法视为字符串,导致一些奇怪的结果}
  • parseFloat() : 将一个字符串转为浮点数
  • isNaN() : 用来判断一个值是否为 NaN

  • isFinite() : 判断某个值是否为正常的数值

字符串

  1. 长字符串分成多行,可在每行尾部使用反斜杠;
  2. 反斜杠(\)表示字符(应该字符的 Unicode 码点)的三种用法:
    • \后面紧跟三个八进制数
    • \x 后面紧跟两个十六进制数
    • \u 后面紧跟四个十六进制数
  3. btoa():任意值转为 Base64 编码
    atob():Base64 编码转为原来的值

对象

对象相关操作
  • Object.keys:查看一个对象本身的所有属性
  • delete:删除对象的属性,删除成功后返回 true,存在且不得删除返回 false
  • in'属性名' in 对象):检查对象是否包含某个属性,包含就返回 true,否则返回 false
  • hasOwnProperty对象.hasOwnProperty('属性名')):判断是否为对象自身的属性
  • for...in:遍历一个对象的全部属性
  • with:方便操作同一个对象的多个属性
    \color{#FF8247}{如果with区块内部有变量的赋值操作,必须是当前对象已经存在的属性,否则会创造一个当前作用域的全局变量。}
    \color{#FF8247}{无法单纯通过代码块判断是全局变量还是对象的一个属性,不利于代码的除错和模块化,拖慢运行速度,所以不建议使用}
var obj = {
  a: 1,
};
with (obj) {
  a = 2;
  b = 3;
}

obj.a // 2;
obj.b // undefined
b // 3;

函数

作用域


举个栗子:

var a = 1;
var x = function () {
  console.log(a);
};
function f() {
  var a = 2;
  x();
}
f() // 1

函数 x 在声明的时候是处于最外层作用域,即使在函数 f 内部被调用,也不会取 f 内部的变量 a 的值,所以会返回 1 而不是 2

参数
  1. 有同名的参数,则取最后出现的那个值;
  2. arguments:函数运行时的所有参数,只有在函数体内部,才可以使用
    • arguments 转为真正的数组的两种方法:
      var args = Array.prototype.slice.call(arguments);
var args = [];
for (var i = 0; i < arguments.length; i++) {
  args.push(arguments[i]);
}
  1. callee:返回它所对应的原函数(可以通过 arguments.callee 调用函数自身)
闭包

闭包的两个最大用处:

  1. 可以读取函数内部的变量,这些变量始终保持在内存中,即闭包的诞生环境一直存在;
    举个栗子:记住上一次调用时的运算结果
function fun(n) {
  return function () {
    return n++;
  };
}
var f = fun(1);
f() // 1
f() // 2
f() // 3
  1. 封装对象的私有属性和私有方法

\color{#FF8247}{外层函数每次运行,都会生成一个新的闭包,而这个闭包又会保留外层函数的内部变量,所以内存消耗很大}

eval

只要不是直接调用,都属于别名调用,别名调用的作用域是全局作用域。

数组
  1. length 最大值是 4294967295;
  2. 数组本质上是对象,所以可以为数组添加属性(但是不影响 length 属性);
函数相关操作

name:返回函数的名字

var myFunc = function () {
  console.log(11111);
}
function test(f) {
  return f.name;
}
eval(test(myFunc))(); //11111
new Function('return ' + test(myFunc))()(); //11111

length:返回函数预期传入的参数个数,即函数定义之中的参数个数
toString:返回函数的源码字符串(原生的函数返回原生代码提示 function (){[native code]}

类型转换

强制转换
  1. Number() —— 数字
    转换规则

a. 原始类型值
Number(123) —— 123
Number('123') —— 123
Number('123abc') —— NaN
Number('') —— 0
Number(true) —— 1
Number(false) —— 0
Number(undefined) —— NaN
Number(null) —— 0
b. 对象
Number({a: 1}) —— NaN
Number([1, 2, 3]) —— NaN
Number([1]) —— 1

  1. String() —— 字符串
    转换规则同 Number() 只是调换了 valueOf()toString() 的顺序。
    a. 原始类型值
    String(123) —— "123"
    String('abc') —— "abc"
    String(true) —— "true"
    String(undefined) —— "undefined"
    String(null) —— "null"
    b. 对象
    String({a: 1}) —— "[object Object]"
    String([1, 2, 3]) —— "1,2,3"
  2. Boolean() —— 布尔值
    undefinednullfalse0NaN、" "、' ' 为 false,其他都为 true
    空数组([])和空对象({}),都是 true
隐式转换:
  1. 不同类型的数据互相运算(+-*/
    • +:有可能转为字符串
      注:
      '1' + {} —— "1[object Object]"
      '1' + function (){} —— "1function (){}"
      '1' + undefined —— "1undefined"
      '1' + null —— "1null"
    • -*/:转成数值
  2. 对非布尔值类型的数据求布尔值
    • !():同 Boolean()
  3. 对非数值类型的值使用一元运算符(+/-
    • 转成数值
      注:
      +{} —— NaN
      +{a: 1} —— NaN
      +[] —— 0
      +[1, 2] —— NaN
  4. 比较判断(===!====!=>>=<<=
    • 转成布尔值

你可能感兴趣的:(JavaScript 查缺补漏)