最近有空看了一点《js 高级程序设计》中变量和内存的章节,对变量和内存问题做了总结整理,其中包含了面试中一些老生常谈的问题,并且穿插了一些看似简单却一不小心就掉坑里的小代码题,假如你在面试中被问到,不知道能不能给面试官留下机敏过人的好印象呢?如果你也感兴趣,那就继续往下看吧。
成都创新互联是专业的相山网站建设公司,相山接单;提供做网站、网站建设,网页设计,网站设计,建网站,PHP网站建设等专业做网站服务;采用PHP框架,可快速的进行相山网站开发网页制作和功能扩展;专业做搜索引擎喜爱的网站,专业的做网站团队,希望更多企业前来合作!
本文涉及以下知识点
一 基础数据类型
8 种。undefined、Null、Boolean、Number、String、symbol、bigInt、object。
1.1 基本类型
7 种。undefined、Null、Boolean、Number、String、symbol、bigInt。其中两种较为特殊的稍作解释。
symbol
每个从Symbol()返回的 symbol 值都是唯一的。一个 symbol 值能作为对象属性的标识符;这是该数据类型仅有的目的。
- Symbol('1') == Symbol('1') // false
作为构造函数来说它并不完整,因为它不支持语法:new Symbol()。
- Symbol(1) //Symbol(1)
- new Symbol(1) // Uncaught TypeError: Symbol is not a constructor
Q1. 如果一个对象的 key 是用 Symbol 创建的,如何获取该对象下所有的 key ,至少说出两种?
A1. Object.getOwnPropertyNames Object.getOwnPropertySymbols 或者 Reflect.ownKeys
Q2. typeof Symbol 和 typeof Symbol()分别输出什么?
A2.
- typeof Symbol //"function"
- typeof Symbol() //"symbol"
bigInt
BigInt 是一种数字类型的数据,它可以表示任意精度格式的整数。目的是安全地使用更加准确的时间戳,大整数 ID 等,是 chrome 67 中的新功能。Number类型只能安全地表示-9007199254740991 (-(2^53-1)) 和9007199254740991(2^53-1)之间的整数,超出此范围的整数值可能失去精度。
- 9007199254740991 //9007199254740991
- 9007199254740992 //9007199254740992
- 9007199254740993 //9007199254740992 !!
创建BigInt在整数的末尾追加 n,或者调用BigInt()构造函数。
- 9007199254740993n //9007199254740993n
- BigInt('9007199254740993') //9007199254740993n
- BigInt(9007199254740993) //9007199254740992n !!
BigInt 和 Number不是严格相等的,但是宽松相等的。
- 9n == 9
- //true
- 9n === 9
- //false
1.2 引用类型
object 里面包含的 function、Array、Date、RegExp。
1.3 null 和 undefined 的区别
undefined读取一个没有被赋值的变量,null定义一个空对象,是一个不存在的对象的占位符
null和undefined转换成 number 数据类型结果不同。null转成0,undefined转成NaN
- new Number(null) //Number {0}
- new Number(undefined) //Number {NaN}
2.1 typeof
只适用于判断基本数据类型(除null外)。null,表示一个空对象指针,返回object。对于对象来说,除了 function 能正确返回 function,其余也都返回object。
- var a;
- console.log(a);//undefined
- console.log(typeof a); //undefined
- typeof typeof 1 //"string"
2.2 instanceof
判断 A 是否是 B 的实例,A instanceof B,用于判断已知对象类型或自定义类型。
- function Beauty(name, age) {
- this.name = name;
- this.age = age;
- }
- var beauty = new Beauty("lnp", 18);
- beauty instanceof Beauty // true
Q1.
- Object instanceof Function // true
- Function instanceof Object // true
- Object instanceof Object // true
- Function instanceof Function // true
2.3 constructor
constructor 不能用于判断undefined 与 null,因为它们没有构造函数。
实用场景小程序中,WXS 不支持使用 Array 对象,因此我们平常用于判断数组类型[] instanceof Array就不能使用了,而typeof []输出结果是object,并不能满足要求。这个时候就可以用constructor 属性进行类型判断:[].constructor === Array //true。
2.4 toString
Object.prototype.toString.call()判断某个对象属于哪种内置类型。是判断数据类型最严谨通用的方法。
- Object.prototype.toString.call(null); // "[object Null]"
- Object.prototype.toString.call(undefined); // "[object Undefined]"
- Object.prototype.toString.call(true);// "[object Boolean]"
- Object.prototype.toString.call(123);// "[object Number]"
- Object.prototype.toString.call(“lnp”);// "[object String]"
- // 函数类型
- Function Beauty(){console.log(“beautiful lnp”);}
- Object.prototype.toString.call(Beauty);//”[object Function]”
- // 日期类型
- var date = new Date();
- Object.prototype.toString.call(date);//”[object Date]”
- // 数组类型
- var arr = [1,2,3];
- Object.prototype.toString.call(arr);//”[object Array]”
- // 正则表达式
- var reg = /^[\d]{5,20}$/;
- Object.prototype.toString.call(arr);//”[object RegExp]”
- var isNativeJSON = window.JSON && Object.prototype.toString.call(JSON);
- console.log(isNativeJSON);//输出结果为”[object JSON]”说明 JSON 是原生的,否则不是
Q1.
- ({a:1}).toString() //返回什么
- ({a:1}).__proto__ === Object.prototype
- ({a:1}).toString() // [object Object]
基本类型保存在栈内存,引用类型的值保存在堆内存,存储该值的地址(指针)保存在栈内存中,这是因为保存在栈内存的必须是大小固定的数据,而引用类型的大小不固定。
堆和栈的区别
2.1 数据类型的拷贝
Q1. 以下代码输出什么?
- 1 == 1;
- [] == []; //?
- {} == {}; //?
A1. 答对了吗?
- 1 == 1; //true
- [] == []; //false
- {} == {}; //false
原因:原始值的比较是值的比较,值相等时它们就相等(),值和类型都相等时它们就恒等(=) 对象(数组)的比较是引用的比较,即使两个对象包含同样的属性及相同的值,它们也是不相等的。
基本类型
图片复制的时候,在栈内存中重新开辟内存,存放变量 age2,所以在栈内存中分别存放着变量 age、age2 各自的值,修改时互不影响。
引用类型
复制的时候,只复制了栈内存中存储的指针,Beauty 和 Beauty2 的指针指向的是堆内存中的同一个值。
连等赋值 a.x = a = {n:2}
理解了吗?那么题目中的问题就要来喽!准备好了吗?请看下面一小段代码... ...
- var a = {n:1};
- var b = a;
- a.x = a = {n:2}
- console.log(a.x);
- console.log(b.x);
- console.log(a);
- console.log(b);
- // 以上代码输出什么?
答(猜)对了吗?
- undefined
- {n: 2}
- {n: 2}
- {n: 1, x: {n: 2}}
解析我们先来还原一下这道题的执行过程。首先var a = {n:1}; 时,为变量 a 在堆内存中开辟了一块内存空间。图片
当var b = a; 时,将变量 b 的指针指向了堆内存中与 a 相同的内存空间。
a.x = a = {n:2}中由于“.”是优先级最高的运算符,先计算a.x,a.x尚未定义,所以是undefined。
然后赋值运算按照从右往左的顺序解析,执行a = {n:2},a(一层变量)被重新赋值,指向一块新的内存空间。
此时a.x,是指堆中已存在的内存 {n:1 x:undefined }的x属性,可以把a.x当作一个整体A,A的指向此时已经确定了,所以a的指向并不会影响a.x,执行a.x = a,则是把{n:2}赋值给{n:1 x:undefined }的x属性。
到这里函数执行完毕,那我们来看(a.x); (b.x); (a); (b); 分别指向什么就 一目了然了。
这个题考察以下 2 个知识点:
同理,来看一下把a.x = a = {n:2} 换成a = a.x = {n:2}呢?
- var a = {n:1};
- var b = a;
- a = a.x = {n:2}
- console.log(a.x);
- console.log(b.x);
- console.log(a);
- console.log(b);
答案是一样的,原理同上。
2.2 深拷贝和浅拷贝区别
2.3 深拷贝和浅拷贝优劣,常用场景
2.4 实现深浅拷贝的方法和其弊端
深拷贝方法:
JSON.parse()与 JSON.stringify() 针对纯 JSON 数据对象,但是它只能正确处理的对象只有 Number, String, Boolean, Array, 扁平对象。
- let obj = {a:{b:22}};
- let copy = JSON.parse(JSON.stringify(obj));
浅拷贝方法:
2.5 总结
深浅拷贝只针对 Object, Array 这样的复杂对象,浅拷贝只复制一层对象的属性,而深拷贝则递归复制了所有层级。
javaScript 具有自动垃圾收集机制,也就是说,执行环境会负责管理代码执行过程中使用的内存。
那么,是不是我们就可以不管了呢?当然不是啊。开发人员只是无需关注内存是如何分配和回收的,但是仍然要避免自己的操作导致内存无法被跟踪到和回收。
首先,我们来了解一下 js 垃圾回收的原理。在局部作用域中,函数执行完毕,局部变量就没有存在的必要了,因此可以释放他们的内存以供将来使用。这种情况,js 垃圾回收机制很容易做出判断并且回收。垃圾收集器必须跟踪哪个变量有用哪个没用,把不用的打上标记,等待将来合适时机回收。
js 的垃圾收集机制有两种,一种为标记清除,一种为引用计数。
所以对于全局变量,很难确认它什么时候不再需要。
什么是内存泄漏和堆栈溢出,二者关系是什么?
内存泄露是指你不再访问的变量,依然占据着内存空间。堆栈溢出是指调用即进栈操作过多,返回即出栈不够。关系:内存泄漏的堆积最终会导致堆栈溢出。
内存泄漏会导致什么问题?
运行缓慢,崩溃,高延迟
4 种常见的内存泄露陷阱
2 种常见的堆栈溢出
内存泄漏避免策略
刘妮萍: 微医前端工程师。养鱼养花养狗,熬夜蹦迪喝酒。出走半生,归来仍是三年前端工作经验。
当前文章:连等赋值a.x=a={n:2}和a=a.x={n:2}一样吗?
网页URL:http://www.shufengxianlan.com/qtweb/news19/41969.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联