JavaScript 查缺补漏

2019-06-12  本文已影响0人  direwolf_

\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
引用数据类型

引用数据是存在堆内存中的对象,需要通过指向储存对象的内存地址的指针进行访问。
\color{#FF8247}{javascript不允许直接访问堆内存空间中的位置和操作堆内存空间。}
举个栗子:

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
\color{#FF8247}{注:null 返回 object 是因为设计之初只把它当作 object 的一种特殊值。}
\color{#FF8247}{后来 null 独立作为一种单独的数据类型,为了兼容以前的代码,所以 typeof 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)。
\color{#FF8247}{注:小心涉及小数的比较和运算}
0.1 + 0.2 —— 0.30000000000000004
0.1 + 0.2 === 0.3 —— false

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

Number.MAX_VALUE // 1.7976931348623157e+308
Number.MIN_VALUE // 5e-324
数值表示

\color{#FF8247}{注:出现不属于该进制的数字,就会报错}

特殊数值
  1. +0 / -0:除了 (1 / +0) === (1 / -0) // false,正零和负零是等价的;
  2. NaNNaN 不等于任何值,包括它本身;
  3. InfinityInfinityNaN 比较,总是返回 false
数值相关操作

字符串

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

对象

对象相关操作
var obj = {
  a: 1,
};
with (obj) {
  a = 2;
  b = 3;
}

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

函数

作用域

\color{#FF8247}{函数执行时所在的作用域,是定义时的作用域,而不是调用时所在的作用域}
举个栗子:

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:函数运行时的所有参数,只有在函数体内部,才可以使用
    \color{#FF8247}{正常模式下,arguments可以在运行时修改;严格模式下,修改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 调用函数自身)
    \color{#FF8247}{这个属性在严格模式里面是禁用的,因此不建议使用}
闭包

闭包的两个最大用处:

  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]}
\color{#FF8247}{函数内部的注释也可以返回,可以变相实现多行字符串}

类型转换

强制转换
  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. 比较判断(===!====!=>>=<<=
    • 转成布尔值
上一篇下一篇

猜你喜欢

热点阅读