1、在JavaScript的数据中包含以下两种

1 基本类型

  1. NumberBooleanStringNULLUndefined

以及ES6的

  1. Symbol

2 引用类型

  1. ObjectArrayFunctionDate

2、在内存中位置的不同

  • 基本类型:占用空间固定,保存在栈中
  • 引用类型:占用空间不固定,保存在堆中

栈(stack)为自动分配的内存空间,它由系统自动释放;使用一级缓存,被调用时通常处于存储空间中,调用后被立即释放。

堆(heap)则是动态分配的内存,大小不定也不会自动释放。使用二级缓存,生命周期与虚拟机的GC算法有关。

当一个方法执行时,每个方法都会建立自己的内存栈,在这个方法内定义的变量将会逐个放入这块栈内存里,随着方法的执行结束,这个方法的内存栈也将自然销毁了。因此,所有在方法中定义的变量都是放在栈内存中的;栈中存储的是基础变量以及一些对象的引用变量,基础变量的值是存储在栈中,而引用变量存储在栈中的是指向堆中的数组或者对象的地址,这就是为何修改引用类型总会影响到其他指向这个地址的引用变量。

当我们在程序中创建一个对象时,这个对象将被保存到运行时数据区中,以便反复利用(因为对象的创建成本通常较大),这个运行时数据区就是堆内存。堆内存中的对象不会随方法的结束而销毁,即使方法结束后,这个对象还可能被另一个引用变量所引用(方法的参数传递时很常见),则这个对象依然不会被销毁,只有当一个对象没有任何引用变量引用它时,系统的垃圾回收机制才会在核实的时候回收它。

3、赋值、浅复制、深复制

  • 对于基本类型值,赋值、浅拷贝、深拷贝时都是复制基本类型的值给新的变量,之后二个变量之间操作不在相互影响。
  • 对于引用类型值,

    赋值后二个变量指向同一个地址,一个变量改变时,另一个也同样改变;

    浅拷贝后得到一个新的变量,这个与之前的已经不是指向同一个变量,改变时不会使原数据中的基本类型一同改变,但会改变会原数据中的引用类型数据

    深拷贝后得到的是一个新的变量,她的改变不会影响元数据
类型 和原数据是否指向同一对象 第一层数据为基本数据类型 原数据中包含子对象
赋值 改变会使原数据一同改变 改变会使原数据一同改变
浅拷贝 改变不会使原数据一同改变 改变会使原数据一同改变
深拷贝 改变不会使原数据一同改变 改变不会使原数据一同改变
  1. var obj1 = {
  2. 'name' : 'zhangsan',
  3. 'age' : '18',
  4. 'language' : [1,[2,3],[4,5]],
  5. };
  6. var obj2 = obj1;
  7. var obj3 = shallowCopy(obj1);
  8. function shallowCopy(src) {
  9. var dst = {};
  10. for (var prop in src) {
  11. if (src.hasOwnProperty(prop)) {
  12. dst[prop] = src[prop];
  13. }
  14. }
  15. return dst;
  16. }
  17. obj2.name = "lisi";
  18. obj3.age = "20";
  19. obj2.language[1] = ["二","三"];
  20. obj3.language[2] = ["四","五"];
  21. console.log(obj1);
  22. //obj1 = {
  23. // 'name' : 'lisi',
  24. // 'age' : '18',
  25. // 'language' : [1,["二","三"],["四","五"]],
  26. //};
  27. console.log(obj2);
  28. //obj2 = {
  29. // 'name' : 'lisi',
  30. // 'age' : '18',
  31. // 'language' : [1,["二","三"],["四","五"]],
  32. //};
  33. console.log(obj3);
  34. //obj3 = {
  35. // 'name' : 'zhangsan',
  36. // 'age' : '20',
  37. // 'language' : [1,["二","三"],["四","五"]],
  38. //};
2.1、浅拷贝

数组常用的浅拷贝方法有

  1. slice,concat,Array.from()

,以及es6的析构

  1. var arr1 = [1, 2,{a:1,b:2,c:3,d:4}];
  2. var arr2 = arr1.slice();
  3. var arr3 = arr1.concat();
  4. var arr4 = Array.from(arr1);
  5. var arr5 = [...arr1];
  6. arr2[0]=2;
  7. arr2[2].a=2;
  8. arr3[0]=3;
  9. arr3[2].b=3;
  10. arr4[0]=4;
  11. arr4[2].c=4;
  12. arr5[0]=5;
  13. arr5[2].d=5;
  14. // arr1[1,2,{a:2,b:3,c:4,d:5}]
  15. // arr2[2,2,{a:2,b:3,c:4,d:5}]
  16. // arr3[3,2,{a:2,b:3,c:4,d:5}]
  17. // arr4[4,2,{a:2,b:3,c:4,d:5}]
  18. // arr5[5,2,{a:2,b:3,c:4,d:5}]

对象常用的浅拷贝方法Object.assign(),es6析构

  1. var obj1 = {
  2. x: 1,
  3. y: {
  4. m: 1
  5. }
  6. };
  7. var obj2 = Object.assign({}, obj1);
  8. console.log(obj1) //{x: 1, y: {m: 1}}
  9. console.log(obj2) //{x: 1, y: {m: 1}}
  10. obj2.x=2;
  11. obj2.y.m = 2; //修改obj2.y.m
  12. console.log(obj1) //{x: 1, y: {m: 2}}
  13. console.log(obj2) //{x: 2, y: {m: 2}}

我们自己实现一个浅拷贝

  1. var obj = { a:1, arr: [2,3] };
  2. var shallowObj = shallowCopy(obj);
  3. var shallowCopy = function(obj) {
  4. // 只拷贝对象
  5. if (typeof obj !== 'object') return;
  6. // 根据obj的类型判断是新建一个数组还是对象
  7. var newObj = obj instanceof Array ? [] : {};
  8. // 遍历obj,并且判断是obj的属性才拷贝
  9. for (var key in obj) {
  10. if (obj.hasOwnProperty(key)) {
  11. newObj[key] = obj[key];
  12. }
  13. }
  14. return newObj;
  15. }
2.2深拷贝

比较简单粗暴的的做法是使用JSON.parse(JSON.stringify(obj))

  1. var arr = ['old', 1, true, ['old1', 'old2'], {old: 1}]
  2. var new_arr = JSON.parse( JSON.stringify(arr) );
  3. new_arr[4].old=4;
  4. console.log(arr); //['old', 1, true, ['old1', 'old2'], {old: 1}]
  5. console.log(new_arr); //['old', 1, true, ['old1', 'old2'], {old: 4}]

JSON.parse(JSON.stringify(obj)) 看起来很不错,不过MDN文档 的描述有句话写的很清楚:

undefined、任意的函数以及 symbol 值,在序列化过程中会被忽略(出现在非数组对象的属性值中时)或者被转换成 null(出现在数组中时)。

但是在平时的开发中JSON.parse(JSON.stringify(obj))已经满足90%的使用场景了。

下面我们自己来实现一个

  1. var deepCopy = function(obj) {
  2. if (typeof obj !== 'object') return;
  3. var newObj = obj instanceof Array ? [] : {};
  4. for (var key in obj) {
  5. if (obj.hasOwnProperty(key)) {
  6. newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key];
  7. }
  8. }
  9. return newObj;
  10. }

3、参数传递

所有的函数参数都是按值传递。也就是说把函数外面的值赋值给函数内部的参数,就和把一个值从一个变量赋值给另一个一样;

  • 基本类型
  1. var a = 2;
  2. function add(x) {
  3. return x = x + 2;
  4. }
  5. var result = add(a);
  6. console.log(a, result); // 2 4
  • 引用类型
  1. function setName(obj) {
  2. obj.name = 'laowang';
  3. obj = new Object();
  4. obj.name = 'Tom';
  5. }
  6. var person = new Object();
  7. setName(person);
  8. console.log(person.name); //laowang

很多人错误地以为在局部作用域中修改的对象在全局作用域中反映出来就是说明参数是按引用传递的。

但是通过上面的例子可以看出如果person是按引用传递的最终的person.name应该是Tom。

实际上当函数内部重写obj时,这个变量引用的就是一个局部变量了。而这个变量会在函数执行结束后销毁。(这是是在js高级程序设计看到的,还不是很清楚)

4、判断方法

基本类型用typeof,引用类型用instanceof

特别注意typeof null是"object", null instanceof Object是true;

  1. console.log(typeof "Nicholas"); // "string"
  2. console.log(typeof 10); // "number"
  3. console.log(typeof true); // "boolean"
  4. console.log(typeof undefined); // "undefined"
  5. console.log(typeof null); // "object"
  6. var items = [];
  7. var obj = {};
  8. function reflect(value){
  9. return value;
  10. }
  11. console.log(items instanceof Array); // true;
  12. console.log(obj instanceof Object); // true;
  13. console.log(reflect instanceof Function); // true;

5、总结

参考链接:

https://mp.weixin.qq.com/s/9IjZHHk3e-BtyPAKgc5DPA

https://segmentfault.com/a/1190000018745719

关于JavaScript中的基本类型的更多相关文章

  1. JavaScript中判断对象类型方法大全1

    我们知道,JavaScript中检测对象类型的运算符有:typeof.instanceof,还有对象的constructor属性: 1) typeof 运算符 typeof 是一元运算符,返回结果是一 ...

  2. JavaScript中判断对象类型的种种方法

    我们知道,JavaScript中检测对象类型的运算符有:typeof.instanceof,还有对象的constructor属性: 1) typeof 运算符 typeof 是一元运算符,返回结果是一 ...

  3. 转 JavaScript中判断对象类型的种种方法

    我们知道,JavaScript中检测对象类型的运算符有:typeof.instanceof,还有对象的constructor属性: 1) typeof 运算符 typeof 是一元运算符,返回结果是一 ...

  4. JavaScript中两种类型的全局对象/函数【转】

    Snandy Stop, thinking is the essence of progress. JavaScript中两种类型的全局对象/函数 这里所说的JavaScript指浏览器环境中的包括宿 ...

  5. JavaScript中判断变量类型最简洁的实现方法以及自动类型转换(#################################)

    这篇文章主要介绍了JavaScript中判断整字类型最简洁的实现方法,本文给出多个判断整数的方法,最后总结出一个最短.最简洁的实现方法,需要的朋友可以参考下 我们知道JavaScript提供了type ...

  6. javaScript中Number数字类型方法入门

    前言 Number和Math都属于JavaScript中的内置对象,Number数字类型作为基础数据类型,我们在开发过程中会经常用到,包括数字精度的格式化,还有字符串转换成数字等操作. Number数 ...

  7. JavaScript中判断对象类型方法大全2

    在JavaScript中,有5种基本数据类型和1种复杂数据类型,基本数据类型有:Undefined, Null, Boolean, Number和String:复杂数据类型是Object,Object ...

  8. javascript中对变量类型的推断

    本文正式地址:http://www.xiabingbao.com/javascript/2015/07/04/javascript-type 在JavaScript中,有5种基本数据类型和1种复杂数据 ...

  9. JavaScript中的Array类型详解

    与其他语言中的数组的区别: 1.JavaScript数组的每一项都可以保存任何类型的数据,一个数组的数组元素可以是不同类型的数据. 2.数组的大小是动态调整的,可以随着数据的添加自动的增长. 1.两种 ...

  10. javascript中对变量类型的判断

    本文正式地址:http://www.xiabingbao.com/javascript/2015/07/04/javascript-type 在JavaScript中,有5种基本数据类型和1种复杂数据 ...

随机推荐

  1. Spring Cloud Hystrix熔断器隔离方案

      Hystrix组件提供了两种隔离的解决方案:线程池隔离和信号量隔离.两种隔离方式都是限制对共享资源的并发访问量,线程在就绪状态.运行状态.阻塞状态.终止状态间转变时需要由操作系统调度,占用很大的性 ...

  2. Go-语言基础-变量-类型-函数

    第一个程序 //单行注释 /* 多行注释 */ package main // 表示当前go文件属于main包 import "fmt" // 导入包 //编译型语言需要有一个入口 ...

  3. vue wangeditor3封装

      <script src="wangEditor/3.1.1/wangEditor.min.js"></script> Vue.component('my ...

  4. python字符串——"奇葩“的内置函数

      一.前言 python编程语言里的字符串与我们初期所学的c语言内的字符串还是有一定不同的,比如python字符串里的内置函数就比语言的要多得多:字符串内的书写格式也会有一点差异,例:字符串内含有引 ...

  5. Spring核心实现篇

    一.Spring Framework的核心:IoC容器的实现 1.1Spring IoC的容器概述 1.1.1 IoC容器和控制反转模式 依赖控制反转的实现有很多种方式.在Spring中,IOC容器是 ...

  6. 关于luoguU67856 数列一题

    本题采用累加法 首先这个式子\[a_n = ka_{n-1}+b\]的通项不用我说了吧 然后就是累加法 \[S_n = \sum_{i=1}^{n} a_i = \sum_{i=1}^{n} ka_{ ...

  7. 格式化输入 \_\_format\_\_

    格式化输入 __format__ 格式化输入 一.__format__ 自定制格式化字符串 date_dic = { 'ymd': '{0.year}:{0.month}:{0.day}', 'dmy ...

  8. android新闻项目、饮食助手、下拉刷新、自定义View进度条、ReactNative阅读器等源码

    Android精选源码 Android仿照36Kr官方新闻项目课程源码 一个优雅美观的下拉刷新布局,众多样式可选 安卓版本的VegaScroll滚动布局 android物流详情的弹框 健身饮食记录助手 ...

  9. LeetCode——919.完全二叉树插入器

    完全二叉树是每一层(除最后一层外)都是完全填充(即,结点数达到最大)的,并且所有的结点都尽可能地集中在左侧. 设计一个用完全二叉树初始化的数据结构 CBTInserter,它支持以下几种操作: CBT ...

  10. java select单线程 服务器

    package com.Select; /** *select单线程 服务器 **/ import java.io.IOException; import java.net.InetSocketAdd ...