javascript: 数据类型深入理解
1.基本类型(值类型或者原始类型): Number、Boolean、String、NULL、Undefined以及ES6的Symbol
2.引用类型:Object、Array、Function、Date等
1 、在内存中的位置不同
基本类型: 占用空间固定,保存在栈中;
引用类型:占用空间不固定,保存在堆中;
栈(stack)为自动分配的内存空间,它由系统自动释放;使用一级缓存,被调用时通常处于存储空间中,调用后被立即释放。
堆(heap)则是动态分配的内存,大小不定也不会自动释放。使用二级缓存,生命周期与虚拟机的GC算法有关
当一个方法执行时,每个方法都会建立自己的内存栈,在这个方法内定义的变量将会逐个放入这块栈内存里,随着方法的执行结束,这个方法的内存栈也将自然销毁了。因此,所有在方法中定义的变量都是放在栈内存中的;栈中存储的是基础变量以及一些对象的引用变量,基础变量的值是存储在栈中,而引用变量存储在栈中的是指向堆中的数组或者对象的地址,这就是为何修改引用类型总会影响到其他指向这个地址的引用变量。
当我们在程序中创建一个对象时,这个对象将被保存到运行时数据区中,以便反复利用(因为对象的创建成本通常较大),这个运行时数据区就是堆内存。堆内存中的对象不会随方法的结束而销毁,即使方法结束后,这个对象还可能被另一个引用变量所引用(方法的参数传递时很常见),则这个对象依然不会被销毁,只有当一个对象没有任何引用变量引用它时,系统的垃圾回收机制才会在核实的时候回收它。
2、赋值、浅拷贝、深拷贝
对于基本类型值,赋值、浅拷贝、深拷贝时都是复制基本类型的值给新的变量,之后二个变量之间操作不在相互影响。
对于引用类型值,
赋值后二个变量指向同一个地址,一个变量改变时,另一个也同样改变;
浅拷贝后得到一个新的变量,这个与之前的已经不是指向同一个变量,改变时不会使原数据中的基本类型一同改变,但会改变会原数据中的引用类型数据
深拷贝后得到的是一个新的变量,她的改变不会影响元数据

var obj1 = {
'name' : 'zhangsan',
'age' : '18',
'language' : [1,[2,3],[4,5]],
};
var obj2 = obj1;
var obj3 = shallowCopy(obj1);
function shallowCopy(src) {
var dst = {};
for (var prop in src) {
if (src.hasOwnProperty(prop)) {
dst[prop] = src[prop];
}
}
return dst;
}
obj2.name = "lisi";
obj3.age = "20";
obj2.language[1] = ["二","三"];
obj3.language[2] = ["四","五"];
console.log(obj1);
//obj1 = {
// 'name' : 'lisi',
// 'age' : '18',
// 'language' : [1,["二","三"],["四","五"]],
//};
console.log(obj2);
//obj2 = {
// 'name' : 'lisi',
// 'age' : '18',
// 'language' : [1,["二","三"],["四","五"]],
//};
console.log(obj3);
//obj3 = {
// 'name' : 'zhangsan',
// 'age' : '20',
// 'language' : [1,["二","三"],["四","五"]],
//};
2.1、浅拷贝
数组常用的浅拷贝方法有slice,concat,Array.from() ,以及es6的析构
var arr1 = [1, 2,{a:1,b:2,c:3,d:4}];
var arr2 = arr1.slice();
var arr3 = arr1.concat();
var arr4 = Array.from(arr1);
var arr5 = [...arr1];
arr2[0]=2;
arr2[2].a=2;
arr3[0]=3;
arr3[2].b=3;
arr4[0]=4;
arr4[2].c=4;
arr5[0]=5;
arr5[2].d=5;
// arr1[1,2,{a:2,b:3,c:4,d:5}]
// arr2[2,2,{a:2,b:3,c:4,d:5}]
// arr3[3,2,{a:2,b:3,c:4,d:5}]
// arr4[4,2,{a:2,b:3,c:4,d:5}]
// arr5[5,2,{a:2,b:3,c:4,d:5}]
对象常用的浅拷贝方法Object.assign(),es6析构
var obj1 = {
x: 1,
y: {
m: 1
}
};
var obj2 = Object.assign({}, obj1);
console.log(obj1) //{x: 1, y: {m: 1}}
console.log(obj2) //{x: 1, y: {m: 1}}
obj2.x=2;
obj2.y.m = 2; //修改obj2.y.m
console.log(obj1) //{x: 1, y: {m: 2}}
console.log(obj2) //{x: 2, y: {m: 2}}
自己实现一个浅拷贝
var obj = { a:1, arr: [2,3] };
var shallowObj = shallowCopy(obj);
var shallowCopy = function(obj) {
// 只拷贝对象
if (typeof obj !== 'object') return;
// 根据obj的类型判断是新建一个数组还是对象
var newObj = obj instanceof Array ? [] : {};
// 遍历obj,并且判断是obj的属性才拷贝
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = obj[key];
}
}
return newObj;
}
2.2、深拷贝
比较简单粗暴的的做法是使用JSON.parse(JSON.stringify(obj))
var arr = ['old', 1, true, ['old1', 'old2'], {old: 1}]
var new_arr = JSON.parse( JSON.stringify(arr) );
new_arr[4].old=4;
console.log(arr); //['old', 1, true, ['old1', 'old2'], {old: 1}]
console.log(new_arr); //['old', 1, true, ['old1', 'old2'], {old: 4}]
undefined、任意的函数以及 symbol 值,在序列化过程中会被忽略(出现在非数组对象的属性值中时)或者被转换成 null(出现在数组中时)。
var deepCopy = function(obj) {
if (typeof obj !== 'object') return;
var newObj = obj instanceof Array ? [] : {};
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key];
}
}
return newObj;
}
3、参数的传递
所有的函数参数都是按值传递。也就是说把函数外面的值赋值给函数内部的参数,就和把一个值从一个变量赋值给另一个一样;
基本类型
var a = 2;
function add(x) {
return x = x + 2;
}
var result = add(a);
console.log(a, result); // 2 4
引用类型
function setName(obj) {
obj.name = 'laowang';
obj = new Object();
obj.name = 'Tom';
}
var person = new Object();
setName(person);
console.log(person.name); //laowang
很多人错误地以为在局部作用域中修改的对象在全局作用域中反映出来就是说明参数是按引用传递的。
但是通过上面的例子可以看出如果person是按引用传递的最终的person.name应该是Tom。
实际上当函数内部重写obj时,这个变量引用的就是一个局部变量了。而这个变量会在函数执行结束后销毁。
4、判断方法
基本类型用typeof,引用类型用instanceof
特别注意
typeof null是"object",null instanceof Object是true;
console.log(typeof "Nicholas"); // "string"
console.log(typeof 10); // "number"
console.log(typeof true); // "boolean"
console.log(typeof undefined); // "undefined"
console.log(typeof null); // "object" var items = [];
var obj = {};
function reflect(value){
return value;
} console.log(items instanceof Array); // true;
console.log(obj instanceof Object); // true;
console.log(reflect instanceof Function); // true;

javascript: 数据类型深入理解的更多相关文章
- Javascript:Javascript数据类型详解
要成为一个优秀的前端工程师,系统的学习Javascript,有夯实的Javascript基础,以及对语言本身的深刻的理解,是基本功.从Javascript数据类型开始,我将对Javascript知识体 ...
- 数据的分类-JavaScript数据类型
JavaScript数据类型 1.数据类型是什么? 我们接触的绝大多数程序语言来说,把数据都进行了分类,包括数字.字符.逻辑真假:int,long,string,boolean....等等:我们都知道 ...
- js基础--javaScript数据类型你都弄明白了吗?绝对干货
欢迎访问我的个人博客:http://www.xiaolongwu.cn 数据类型的分类 JavaScript的数据类型分为两大类,基本数据类型和复杂数据类型. 基本数据类型:Null.Undefine ...
- JavaScript 数据类型检测总结
JavaScript 数据类型检测总结 原文:https://blog.csdn.net/q3254421/article/details/85483462 在js中,有四种用于检测数据类型的方式,分 ...
- JavaScript筑基篇(二)->JavaScript数据类型
说明 介绍JavaScript数据类型 目录 前言 参考来源 前置技术要求 JavaScript的6种数据类型 哪6种数据类型 undefined 类型 null 类型 boolean 类型 numb ...
- 02 JavaScript数据类型、类型转换、注释
JavaScript 数据类型 JavaScript 变量能够保存多种数据类型:数值.字符串值.数组.对象.undefined.null等等 var length = 7; // 数字 var las ...
- JavaScript数据类型 typeof, null, 和 undefined
JavaScript 数据类型 在 JavaScript 中有 5 种不同的数据类型: string number boolean object function 3 种对象类型: Object Da ...
- javascript单例模式的理解
javascript单例模式的理解 阅读目录 理解单例模式 使用代理实现单例模式 理解惰性单例 编写通用的惰性单例 单例模式使用场景 回到顶部 理解单例模式 单例模式的含义是: 保证一个类只有一个实例 ...
- 网页、JavaScript 数据类型
JavaScript 数据类型 一.基本数据类型: 字符串.数字.布尔.日期和时间 JavaScript 拥有动态类型 JavaScript 拥有动态类型.这意味着相同的变量可用作不同的类型: 1 v ...
随机推荐
- shell 环境变量的知识小结
环境变量的知识小结:·变量名通常要大写.·变量可以在自身的Shell及子Shell中使用.·常用export来定义环境变量.·执行env默认可以显示所有的环境变量名称及对应的值.·输出时用“$变量名” ...
- 4.windows如何导入python包
python链接:https://www.python.org/downloads/release/python-2715/ pip链接:https://pypi.org/project/pip/#f ...
- uva The Tower of Babylon[LIS][dp]
转自:https://mp.weixin.qq.com/s/oZVj8lxJH6ZqL4sGCXuxMw The Tower of Babylon(巴比伦塔) Perhaps you have hea ...
- linux进程间通讯的几种方式的特点和优缺点
# 管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用.进程的亲缘关系通常是指父子进程关系.# 有名管道 (named pipe) : 有名管道也是 ...
- 2.5 The Object Model -- Observers
Ember支持监视任何属性,包括计算的属性.你可以使用Ember.observer为一个对象设置一个监视者: Person = Ember.Object.extend({ //these will b ...
- 通过IP地址和子网掩码与运算计算相关地址
通过IP地址和子网掩码与运算计算相关地址 知道IP地址和子网掩码后可以算出 网络地址 广播地址 地址范围 本网有几台主机 例一:下面例子IP地址为192.168.100.5 子网掩码是255.255. ...
- 散列表Java实现
package 散列表; import java.util.Scanner; public class HashSearch { public static int data[] = {69,65,9 ...
- git使用多个SSH公钥信息
常常在开发环境存在多个git库,比如官方的github.公司搭建的gitlab.自己的私人库等等多个git库,为了方便使用,git需要配置多个SSH公钥信息. 在centos7.5下,进入用户目录,以 ...
- Linux的crontab
如果要让unix系统重复,定期做一件事,我们就会用到crontab. 实质上真正去执行每一个重复任务的是cron,cron是的unix家族的一个后台常驻程序,cron是由cron文件来驱动的,cron ...
- awk处理excel表格数据
拿到一个ip的excel表格,要对单元格中的ip进行扫描,一看有点乱,有空格分割的,有"/"分割的,有带括号(分割的,有好几百个: 要把左边的变为右边的格式,用excel自带的功能 ...