JavaScript 数据类型

基本数据类型

JavaScript基本数据类型有Number,String,Boolean,Null,Undefined,symbol,bigint。其中symbol,bigint是ES6新增的。

Number-数字

JavaScript 的Number类型为双精度 IEEE 754 64 位浮点类型。JavaScript 不区分整数值和浮点数值,所有数字在 JavaScript 中均用浮点数值表示,所以在进行数字运算的时候要特别注意进度缺失问题。

为什么0.1 + 0.2 != 0.3 ?

因为浮点数运算的精度问题。在计算机运行过程中,需要将数据转化成二进制,然后再进行计算。js中的Number类型遵循IEEE754标准,在IEEE754标准的64位浮点数相加,因为浮点数自身小数位数的限制而截断的二进制在转化为十进制,就变成0.30000000000000004,所以在计算时会产生误差。

解决方案:

  • 第一种:NumberObject.toFixed(num)
    NumberObject.toFixed(num) 方法可把 Number 四舍五入为指定小数位数的数字。num规定小数的位数,取值范围 [0, 20] ,默认值为0。

var num = new Number(13.37);
console.log(num.toFixed(1));//13.4
  • 第二种:Number.EPSILON
    Number.EPSILON属性表示 1 与Number可表示的大于 1 的最小的浮点数之间的差值。可以用来设置“能够接受的误差范围”。比如,误差范围设为 2 的-50 次方,如果两个浮点数的差小于这个值,我们就认为这两个浮点数相等。

var x = 0.2;
var y = 0.3;
var z = 0.1;
var equal = (x + z - y) == 0;//false
var var equal = ((x + z - y) < Number.EPSILON);//true

String-字符串

字符串可以存储一系列字符,如 "zhang"。字符串可以是插入到引号中的任何字符。可以使用单引号或双引号。

var s = 'aidsfjiajdpof';
var b = s.length;//13
var c = s[3];//s

Boolean-布尔类型

 布尔(逻辑)只能有两个值:true 或 false。

Null和Undefined

Null 和 Undefined 都代表空,主要区别在于 undefined 表示尚未初始化的变量的值,而 null 表示该变量有意缺少对象指向。

引用/复杂数据类型

JavaScript引用/复杂数据类型有Array、Object、Function。

Array-数组

  • 创建数据的方法

1. 创建数组并给数组赋值

var myCars = new Array();
myCars[0] = "Saab";
myCars[1] = "Volvo";
myCars[2] = "BMW";

2. 直接实例化

var myCars = new Array("Saab","Volvo","BMW");

3. 字面-隐式创建

var myCars = ["Saab","Volvo","BMW"];
  • 数组的常用操作

1. concat()

  用于连接两个或多个数组,返回新数组不会改变现有的数组。

var arr1 = [1, 2, 3]
var arr2 = arr1.concat(arr1, 22);
console.log(arr1 === arr2); //false
console.log(arr1.concat("hello", "world")); //[1,2,3,"hello","world"]
console.log(arr1.concat(["a", "b"], [[3, 4], {"name": "admin"}])); //[1,2,3,"a","b",[3,4],{"name":"admin"}]
console.log(arr1); //[1,2,3]---原数组未改变

2. join()

根据指定分隔符将数组中的所有元素连接放入一个字符串,并返回这个字符串。join(str);参数默认为","号。不改变原数组。

var arr = [1,2,3];
console.log(arr.join());         //1,2,3
console.log(arr.join("-"));      //1-2-3
console.log(arr);                //[1,2,3]---原数组未改变

3. pop()

用于删除并返回数组的最后一个元素。原数组改变。

4. shift()

用于删除并返回数组的第一个元素。原数组改变。

5. unshift()

向数组的开头添加一个或多个元素,并返回新的长度。原数组改变。

6. push()

向数组的末尾添加一个或更多元素,并返回新的长度。原数组改变。

7. reverse()

翻转数组中元素的顺序。原数组改变。

8. slice()

从已有的数组中返回选定的元素。该方法接收两个参数slice(start,end),strat为必选,表示从第几位开始;end为可选,表示到第几位结束(不包含end位),省略表示到最后一位;start和end都可以为负数,负数时表示从最后一位开始算起,如-1表示最后一位。不改变原数组。

    var arr = ["A","B","C","D","E"];
    console.log(arr.slice(1,3));        //["B","C"]
    console.log(arr.slice(1));          //["B","C","D","E"]
    console.log(arr.slice(-4,-1));      //["B","C","D"]
    console.log(arr.slice(-2));         //["D","E"]
    console.log(arr.slice(1,-2));       //["B","C"]
    console.log(arr);                   //["A","B","C","D","E"]---原数组未改变

9. sort()

对数组中的元素进行排序,默认是升序。原数组改变。

注意:但是在排序前,会先调用数组的toString方法,将每个元素都转成字符之后,再进行排序,此时会按照字符串的排序,逐位比较,进行排序。

var arr = [6,1,5,2,3];
console.log(arr.sort());    //[1, 2, 3, 5, 6]
console.log(arr);           //[1, 2, 3, 5, 6]---原数组改变
var arr1 = [6,1024,52,256,369];
console.log(arr1.sort());    //[1024, 256, 369, 52, 6]
console.log(arr1);           //[1024, 256, 369, 52, 6]---原数组改变

解决方法:sort(compareFunction),如果需要按照数值排序,需要传参。compareFunction为回调函数,该函数应该具有两个参数,比较这两个参数,然后返回一个用于说明这两个值的相对顺序的数字。

  • 如果 compareFunction(a, b) 小于 0 ,那么 a 会被排列到 b 之前;
  • 如果 compareFunction(a, b) 等于 0 , a 和 b 的相对位置不变。
  • 如果 compareFunction(a, b) 大于 0 , b 会被排列到 a 之前。
  • compareFunction(a, b) 必须总是对相同的输入返回相同的比较结果,否则排序的结果将是不确定的
var arr = [6,1024,52,256,369];
console.log(arr.sort(fn));  //[6, 52, 256, 369, 1024]
console.log(arr);           //[6, 52, 256, 369, 1024]---原数组改变
function fn(a,b){
   return a-b;
}

10. splice()

向数组中添加,或从数组删除,或替换数组中的元素,然后返回被删除/替换的元素。原数组为修改后的数组。array.splice(start,deleteCount,item1, item2, ...)

start​指定修改的开始位置(从 0 计数)。

deleteCount :表示要移除的数组元素的个数。

item1, item2, ... :要添加进数组的元素,从start 位置开始。如果不指定,则 splice() 将只删除数组元素。

返回值:由被删除的元素组成的一个数组。如果只删除了一个元素,则返回只包含一个元素的数组。如果没有删除元素,则返回空数组。

11. toString()

转换成字符串,类似于没有参数的join()。该方法会在数据发生隐式类型转换时被自动调用,如果手动调用,就是直接转为字符串。不改变原数组。

var arr = [1,2,3];
console.log(arr.toString());     //1,2,3
console.log(arr);                //[1,2,3]---原数组未改变

12. valueOf()

返回数组的原始值(一般情况下其实就是数组自身),一般由js在后台调用,并不显式的出现在代码中

    var arr = [1,2,3];
    console.log(arr.valueOf());         //[1,2,3]
    console.log(arr);                   //[1,2,3]
    //为了证明返回的是数组自身
    console.log(arr.valueOf() == arr);  //true

13. indexOf()

根据指定的数据,从左向右,查询在数组中出现的位置,如果不存在指定的数据,返回-1。该方法是查询方法,不会对数组产生改变。indexOf(value, start);value为要查询的数据;start为可选,表示开始查询的位置,当start为负数时,从数组的尾部向前数;如果查询不到value的存在,则方法返回-1。

14. forEach()

ES5新增方法,用来遍历数组,该方法没有返回值。forEach接收的回调函数会根据数组的每一项执行,该回调函数默认有三个参数,分别为:遍历到的数组的数据,对应的索引,数组自身。

const arraySparse = [1,3,7];
let numCallbackRuns = 0;

arraySparse.forEach(function(element){
  console.log(element);
  numCallbackRuns++;
});
//1
//3
//7

15. map()

同forEach功能;map的回调函数会将执行结果返回,最后map将所有回调函数的返回值组成新数组返回

const array1 = [1, 4, 9, 16];
// pass a function to map
const map1 = array1.map(x => x * 2);
console.log(map1);
// expected output: Array [2, 8, 18, 32]

16. filter()

同forEach功能;filter的回调函数需要返回布尔值,当为true时,将本次数组的数据返回给filter,最后filter将所有回调函数的返回值组成新数组返回(此功能可理解为“过滤”)。

const words = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present'];
const result = words.filter(word => word.length > 6);
console.log(result);
// expected output: Array ["exuberant", "destruction", "present"]

17. every()

判断数组中每一项是否都满足条件,只有所有项都满足条件,才会返回true。every 方法为数组中的每个元素执行一次 callback 函数,直到它找到一个会使 callback 返回 false 的元素。如果发现了一个这样的元素,every 方法将会立即返回 false。否则,callback 为每一个元素返回 trueevery 就会返回 trueevery 不会改变原数组。

18. some() 

测试数组中是不是至少有 1 个元素通过了被提供的函数测试。它返回的是一个 Boolean 类型的值。找到符合条件的就立即返回true。

Object-对象

  • 创建对象的方法

1. new Object();

var myCar = new Object();
myCar.make = "Ford";
myCar.model = "Mustang";
myCar.year = 1969; 

2. 使用对象初始化器(通过字面值)创建对象

var obj = {
    name: 'zhang',
    age: 18,
    'address': '吉林',
};

3. 使用构造函数

function Car(make, model, year) {
  this.make = make;
  this.model = model;
  this.year = year;
}
var mycar = new Car("Eagle", "Talon TSi", 1993);

Function-函数

每个 JavaScript 函数实际上都是一个 Function 对象。运行 (function(){}).constructor === Function // true 便可以得到这个结论。

Function 构造函数与函数声明之间的不同

由 Function 构造函数创建的函数不会创建当前环境的闭包,它们总是被创建于全局环境,因此在运行时它们只能访问全局变量和自己的局部变量,不能访问它们被 Function 构造函数创建时所在的作用域的变量。这一点与使用 eval() 执行创建函数的代码不同。

var x = 10;

function createFunction1() {
    var x = 20;
    return new Function('return x;'); // 这里的 x 指向最上面全局作用域内的 x
}

function createFunction2() {
    var x = 20;
    function f() {
        return x; // 这里的 x 指向上方本地作用域内的 x
    }
    return f;
}

var f1 = createFunction1();
console.log(f1());          // 10
var f2 = createFunction2();
console.log(f2());          // 20

Function方法

​​​​​​  1. Function.prototype.apply()

apply() 方法调用一个具有给定 this 值的函数,以及以一个数组(或一个类数组对象)的形式提供的参数。返回值:调用有指定 this 值和参数的函数的结果。

thisArg

在 func 函数运行时使用的 this 值。请注意,this 可能不是该方法看到的实际值:如果这个函数处于非严格模式下,则指定为 null 或 undefined 时会自动替换为指向全局对象,原始值会被包装。

argsArray 可选

一个数组或者类数组对象,其中的数组元素将作为单独的参数传给 func 函数。如果该参数的值为 null 或 undefined,则表示不需要传入任何参数。从 ECMAScript 5 开始可以使用类数组对象。

当第一个参数为 null 或 undefined 时,可以使用数组展开语法实现类似的结果

//用 apply 将数组各项添加到另一个数组
const array = ['a', 'b'];
const elements = [0, 1, 2];
array.push.apply(array, elements);
console.info(array); // ["a", "b", 0, 1, 2]

//使用 apply 和内置函数
const numbers = [5, 6, 2, 3, 7];
// 使用 Math.max 以及 apply 函数时的代码
let max = Math.max.apply(null, numbers); // 基本等同于 Math.max(numbers[0], ...) 或Math.max(5, 6, ..)

//apply第一个参数为nul或undefined时和数组展开语法
function sum(x, y, z) {
  return x + y + z;
}
const numbers = [1, 2, 3];
console.log(sum(...numbers));
// expected output: 6
console.log(sum.apply(null, numbers));
// expected output: 6

2. Function.prototype.bind()

bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。返回一个原函数的拷贝,并拥有指定的 this 值和初始参数。
.bind(thisArg[, arg1[, arg2[, ...]]])

  • 用法一:创建绑定函数

  bind() 最简单的用法是创建一个函数,不论怎么调用,这个函数都有同样的 this 值。JavaScript 新手经常犯的一个错误是将一个方法从对象中拿出来,然后再调用,期望方法中的 this 是原来的对象(比如在回调中传入这个方法)。如果不做特殊处理的话,一般会丢失原来的对象。基于这个函数,用原始的对象创建一个绑定函数,巧妙地解决了这个问题:

this.x = 9;    // 在浏览器中,this 指向全局的 "window" 对象
var module = {
  x: 81,
  getX: function() { return this.x; }
};

module.getX(); // 81

var retrieveX = module.getX;
retrieveX();
// 返回 9 - 因为函数是在全局作用域中调用的

// 创建一个新函数,把 'this' 绑定到 module 对象
var boundGetX = retrieveX.bind(module);
boundGetX(); // 81
  • 用法二:配合setTimeout

     在默认情况下,使用 window.setTimeout() 时,this 关键字会指向 window(或 global)对象。当类的方法中需要 this 指向类的实例时,你可能需要显式地把 this 绑定到回调函数,就不会丢失该实例的引用。

function LateBloomer() {
  this.petalCount = Math.ceil(Math.random() * 12) + 1;
}

// 在 1 秒钟后声明 bloom
LateBloomer.prototype.bloom = function() {
  window.setTimeout(this.declare.bind(this), 1000);
};

LateBloomer.prototype.declare = function() {
  console.log('I am a beautiful flower with ' +
    this.petalCount + ' petals!');
};

var flower = new LateBloomer();
flower.bloom();  // 一秒钟后,调用 'declare' 方法

3. Function.prototype.call()

call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。该方法的语法和作用与 apply() 方法类似,只有一个区别,就是 call() 方法接受的是一个参数列表,而 apply() 方法接受的是一个包含多个参数的数组。如果没有传递第一个参数,this 的值将会被绑定为全局对象。在严格模式('use strict')下,this 的值将会是 undefined

  • 用法一:调用父构造函数
function Product(name, price) {
  this.name = name;
  this.price = price;
}

function Food(name, price) {
  Product.call(this, name, price);
  this.category = 'food';
}

function Toy(name, price) {
  Product.call(this, name, price);
  this.category = 'toy';
}

var cheese = new Food('feta', 5);
var fun = new Toy('robot', 40);
  • 用法二:调用函数指定上下文的'this'
function greet() {
  var reply = [this.animal, 'typically sleep between', this.sleepDuration].join(' ');
  console.log(reply);
}

var obj = {
  animal: 'cats', sleepDuration: '12 and 16 hours'
};

greet.call(obj);  // cats typically sleep between 12 and 16 hours

两种数据类型的存储方式

  • 堆:引用数据类型 -> 对象(Object) 数组(Array) 函数(Function)

  • 栈:原始数据类型

两种数据类型的区别

两种类型的区别主要在于存储位置不同:

原始数据类型直接存放在栈(stack)中的简单数据段,占据空间小,大小固定,属于频繁被使用的数据所以放在栈中存储。引用数据类型存储在堆中的对象,占据空间大,大小不固定。如果将引用数据类型存储在栈中会影响程序运行的性能,引用数据类型是在栈中存储了指针,该指针指向堆中该实体起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。

在数据结构中,栈中数据的存取方式为先进后出,堆是一个优先级队列,按照优先级进行排序。

在操作系统中,内存被分为堆区和栈区,栈区内存由编译器自动分配,存放函数的参数值,局部变量的值等。堆区内存一般由开发者分配释放,若开发者不释放,程序结束时可能由垃圾回收机制回收。

如何判断数据类型

1. typeof

数组、对象、null都会被判断为object

console.log(typeof 2);//number
console.log(typeof true);//boolean
console.log(typeof '2');//string
console.log(typeof []);//object
console.log(typeof {});//object
console.log(typeof function() {});//function
console.log(typeof null);//object
console.log(typeof undefined);//undefined

2. instanceof

instanceof可以正确判断对象的类型,其内部运行机制是通过判断在其原型链中是否能找到该类型的原型。

console.log(2 instanceof Number);//false
console.log(true instanceof Boolean);//false
console.log('2'  instanceof String);//false
console.log([] instanceof Array);//true
console.log({} instanceof Object);//true
console.log(function() {} instanceof Function);//true

3. constructor

constructor可以判断数据类型,对象实例也可以通过constructor访问它的构造函数。但是如果创建一个对象来改变他的原型,constructor就不能用来判断数据类型了。

console.log((2).constructor === Number); //true
console.log((true).constructor === Boolean);//true
console.log(('2').constructor === String);//true
console.log(([]).constructor === Array);//true
console.log(({}).constructor === Object);//true
console.log((function() {}).constructor === Function);//true

function Fn() {};
Fn.prototype = new Array();
var f = new Fn();
console.log(f.constructor === Fn);//false
console.log(f.constructor === Array);//true

4. Object.prototype.toString.call()

var a = Object.prototype.toString;
console.log(a.call(2));//[object Number]
console.log(a.call(true));//[object Boolean]
console.log(a.call('2'));//[object String]
console.log(a.call([]));//[object Array]
console.log(a.call({}));//[object Object]
console.log(a.call(function() {}));//[object Function]

数据类型转换 

1. 把数值、布尔类型转换为字符串

String(x)         // 从数值变量 x 返回字符串
String(123)       // 从数值文本 123 返回字符串
String(100 + 23)  // 从表达式中的数值返回字符串
x.toString()
(123).toString()
(100 + 23).toString()
String(false)        // 返回 "false"
String(false)        // 返回 "false"

2. 把字符串,布尔值转换为数值

Number("3.14")    // 返回 3.14
Number(" ")       // 返回 0
Number("")        // 返回 0
Number("99 88")   // 返回 NaN

var y = "5";      // y 是字符串
var x = + y;      // x 是数字
var y = "Bill";   // y 是字符串
var x = + y;      // x 是数字 (NaN)
Number(false)     // 返回 0
Number(true)      // 返回 1

 3. 自动类型转换

5 + null    // 返回 5         因为 null 被转换为 0
"5" + null  // 返回 "5null"   因为 null 被转换为  "null"
"5" + 2     // 返回 52        因为 2 被转换为 "2"
"5" - 2     // 返回 3         因为 "5" 被转换为 5
"5" * "2"   // 返回 10        因为 "5" 和 "2" 被转换为 5 和 2

ES6新增数据类型

Symbol

Symbol() 函数会返回 symbol 类型的值,该类型具有静态属性和静态方法。它的静态属性会暴露几个内建的成员对象;它的静态方法会暴露全局的 symbol 注册,且类似于内建对象类,但作为构造函数来说它并不完整,因为它不支持语法:"new Symbol()"。每个从 Symbol() 返回的 symbol 值都是唯一的。一个 symbol 值能作为对象属性的标识符;这是该数据类型仅有的目的。

//Symbol("foo") 不会强制将字符串 “foo” 转换成 symbol 类型。它每次都会创建一个新的 symbol 类型
Symbol("foo") === Symbol("foo"); // false

BigInt

BigInt 是一种内置对象,它提供了一种方法来表示大于 2^53 - 1 ( 这原本是 Javascript 中可以用 Number 表示的最大数字)的整数。BigInt 可以表示任意大的整数。 它在某些方面类似于 Number ,但是也有几个关键的不同点:不能用于 Math 对象中的方法;不能和任何 Number 实例混合运算,两者必须转换成同一种类型。在两种类型来回转换时要小心,因为 BigInt 变量在转换成 Number 变量时可能会丢失精度。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值