数据类型

基本类型值包括: undefined,null,Boolean,Number和String,这些类型分别在内存中占有固定的大小空间,它们的值保存在栈空间,我们通过按值来访问的。

引用类型包括:对象、数组、函数等。

对于引用类型的值,则必须在堆内存中为这个值分配空间。由于引用类型值的大小不固定(对象有很多属性和方法,而且还可以动态的添加属性和方法),因此不能把他们保存到栈内存中。但内存地址大小是固定的,因此可以将内存地址保存在栈内存中。

简而言之:栈内存中存放的是基本数据类型值,堆内存中存放的是引用类型值,引用类型值在内存中的地址存放在栈中,也就是我们常说的对象对象引用(指针)。


变量复制

<script type="text/javascript">
var a = 5;
var b = a;
console.log(a+"---"+b);//5---5
b = 6;//这里重新给b赋值,a值并没有改变
console.log(a+"---"+b);//5---6 var obj = {name:"lisi"};
var obj2 = obj;//这里是引用赋值,obj和obj2指向同一个对象
console.log(obj.name + "---" + obj2.name);//lisi---lisi
obj2.name = "wangwu";
console.log(obj.name + "---" + obj2.name);//wangwu---wangwu
</script>
---------------------
作者:自由2017
来源:CSDN
原文:https://blog.csdn.net/liujie19901217/article/details/52088182
版权声明:本文为博主原创文章,转载请附上博文链接!

从上面例子可以看出:在变量复制方面,基本类型和引用类型也有所不同,基本类型复制的是值本身,而引用类型复制的是内存地址。


函数
this 的工作原理(5种情况)

全局作用域内
当在全部作用域内使用 this时,它将会指向全局对象,即window对象

函数调用
挡在全局作用域内调用函数时,this 也会指向全局对象。

方法调用
this 指向调用该方法的对象。

调用构造函数
在构造函数内部,this 指向新创建的对象。

显式的设置this指向
当使用call 或者 apply 方法时,函数内的 this 将会被显式设置为函数调用的第一个参数。
更详细用法请见之前的博客:传送门

匿名函数
在javascript里任何匿名函数都是属于window对象。在定义匿名函数时候它会返回自己的内存地址,如果此时有个变量接收了这个内存地址,那么匿名函数就能在程序里被使用了(可以通过在这个变量后面加一对圆括号来调用这个匿名函数),因为匿名函数也是在全局执行环境构造时候定义和赋值,所以匿名函数的this指向也是window对象。

<script type="text/javascript">
(function(){
console.log(this == window);//true
})();
</script>

参数传递

<script type="text/javascript">
function test(num){//按值传递
num+=5;
console.log(num);
return num;
}
var num = 5;
var result = test(num);
console.log(result);// 10 如果是按引用传递,那么函数里的num会成为类似全局变量,把外面的num覆盖掉
console.log(num);// 5 也就是说,最后应该输出20(这里输出10)
</script>

js中不存在引用传递,如果存在引用传递的话,那么函数内的变量将是全局变量,在外部也可以访问,但这明显是不可能的。
再看一个例子:

<script type="text/javascript">
function setName(obj){//obj = person
obj.name = "lisi";
obj = new Object();
obj.name = "wangwu";
}
var person = new Object();
setName(person);
alert(person.name);
console.log(obj.name);//Uncaught ReferenceError: obj is not defined
</script>

在将person传递给obj后,其name属性就被设置成了”lisi”。又将obj重新定义了一个对象,另一行代码为该对象定义了一个带有不同值的name属性。
如果person是按引用传递的,那么person就会自动被修改为指向其name属性值为”wangwu”的新对象,但事实上并没有,其name属性依然是”lisi”。
这就说明:即使在函数内部修改了参数的值,但原始的引用仍然保持不变。实际上,当在函数内重写obj时,这个变量引用的就是一个局部对象了。而这个局部对象会在函数执行完毕后立即被销毁。


执行环境及作用域

执行环境
执行环境定义了变量或函数有权访问其他数据,可以分为全局执行环境和局部执行环境。
全局执行环境是最外层的执行环境,在浏览器中,全局执行环境是window对象,因此,所有的全局变量的函数都是作为window的属性和方法创建的。
注意:对于局部执行环境,其内部的代码执行完毕后,该环境将被销毁,保存其中的变量和函数也随之销毁,如果是全局执行环境,需所有程序执行完毕或网页完毕后才会销毁。

需要注意的小细节
去掉var的局部变量

<script type="text/javascript">
var name = "wangwu";
function setName(){
name = "lisi";//去掉var变成了全局变量,会覆盖全局中的name
}
setName();
console.log(name);//lisi
</script>

形参也是局部变量

<script type="text/javascript">
var name = "wangwu";
function setName(name){//形参也是局部变量
console.log(name);
}
setName("lisi");//lisi
console.log(name);//wangwu
</script>

作用域
  当代码在一个环境中执行的时候,就会形成作用域链,它的作用是保证对执行环境中有访问权限的变量和函数进行有序访问(内部深层环境可以访问外层环境,反之不成立),作用域链的前端,就是执行环境的变量对象。

详见之前博客:传送门


内存泄漏常见情况

  javascript具有自动垃圾回收机制,一旦数据不再使用,可以将其设为”null”来释放引用。


循环引用
分为两种情况:不同对象之间相互引用和

一个经典的例子:一个DOM对象被一个Javascript对象引用,与此同时又引用同一个或其它的Javascript对象,这个DOM对象可能会引发内存泄露。这个DOM对象的引用将不会在脚本停止的时候被垃圾回收器回收。要想破坏循环引用,引用DOM元素的对象或DOM对象的引用需要被赋值为null。

<body>
<script type="text/javascript">
var oBox = document.getElementById("box");
var obj = {};
oBox.name = obj;
obj.age = oBox;//这样就发生了循环引用
</script>
</body>

闭包(常见)

  通过闭包引用其包含函数的局部变量,当闭包结束后该局部变量无法被垃圾回收机制回收,造成内存泄漏。

DOM泄漏
当原有的DOM被移除时,子结点引用没有被移除则无法回收。

var select = document.querySelector;
var treeRef = select('#tree');
//在COM树中leafRef是treeFre的一个子结点
var leafRef = select('#leaf');
var body = select('body');
body.removeChild(treeRef);
//#tree不能被回收入,因为treeRef还在
//解决方法:
treeRef = null;
//tree还不能被回收,因为叶子结果leafRef还在
leafRef = null;
//现在#tree可以被释放了。

定时器泄漏

for (var i = 0; i < 1000; i++) {
var obj = {
fn: function() {
var that = this;
var val = setTimeout(function() {
that.fn();
}, 500);
}
}
obj.fn();
//虽然你想回收但是timer还在
obj = null;
}

垃圾回收

标记清除
  js中最常用的垃圾回收方式就是标记清除。垃圾收集器在运行的时候回给存储在内存中的所有变量都加上标记。然后,它会去掉环境中的变量以及被环境中的变量引用的变量的标记(闭包)。而在此之后再被加上标记的变量将被视为准备删除的变量,原因是环境中的变量已经无法访问到这些变量了。最后,垃圾收集器完成内存清除工作,消除那些带标记的值并回收它们所占用的内存空间。
例如:在函数中声明一个变量,就将这个变量标记为”进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到它们。而当变量离开环境时,则将其标记为”离开环境”。

function test(){
var x = 10 ; //被标记 ,进入环境
var y = 20 ; //被标记 ,进入环境
}
test(); //执行完毕后 x、y又被标离开环境,被回收。

引用计数
  引用计数就是:跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型值赋给该变量时,则这个值的引用次数就是1。如果同一个值又被赋给另一个变量,则该值的引用次数加1。相反,如果包含对这个值引用的变量又取得了另外一个值,则这个值的引用次数减1。当这个值的引用次数变成0时,则说明没有办法再访问这个值了,因而就可以将其占用的内存空间回收回来。这样,当垃圾回收器下次再运行时,它就会释放那些引用次数为0的值所占用的内存。

function test(){
var x = {} ; //x的引用次数为0
var y = x ; //x的引用次数加1,为1
var z =x; //x的引用次数再加1,为2
var y ={}; //x的引用次数减1,为1
}

引用计数策略的问题(循环引用)

function test() {
var a = {};
var b = {};
a.name = b;
b.name = a;
}
test();

  以上代码a和b的引用次数都是2,fn()执行完毕后,两个对象都已经离开环境,在标记清除方式下是没有问题的,但是在引用计数策略下,因为a和b的引用次数不为0,所以不会被垃圾回收器回收内存,如果fn函数被大量调用,就会造成内存泄露。在IE7与IE8上,内存直线上升。
我们知道,IE中有一部分对象并不是原生js对象。例如,其BOM和DOM中的对象就是使用C++以COM对象的形式实现的,而COM对象的垃圾回收机制采用的就是引用计数策略。因此,即使IE的js引擎采用标记清除策略来实现,但js访问的COM对象依然是基于引用计数策略的。换句话说,只要在IE中涉及COM对象,就会存在循环引用的问题。

var element = document.getElementById("some_element");
var myObject = new Object();
myObject.element = element;
element.someObject = myObject;//产生了循环引用

  这个例子在一个DOM元素(element)与一个原生js对象(myObject)之间创建了循环引用。其中,变量myObject有一个名为element的属性指向element对象;而变量element也有一个someObject属性指向myObject。由于存在这个循环引用,即使例子中的DOM从页面中移除,它也永远不会被回收。

myObject.element = null;
element.someObject = null;

  为了避免类似这样的循环引用问题,最好在不使用它们的时候手工断开原生js对象与DOM元素之间的连接。将变量设置为null意味着切断变量与它此前引用的值之间的连接。当垃圾收集器下次运行时,就会删除这些值并回收它们占用的内存。

注意:为了解决上述问题,IE9把BOM和DOM对象都转换成了真正的js对象。这样,就避免了两种垃圾收集算法并存导致的问题,也消除了常见的内存泄漏现象。

原文:https://blog.csdn.net/liujie19901217/article/details/52088182

原生js总结的更多相关文章

  1. 原生JS封装Ajax插件(同域&amp;&amp;jsonp跨域)

    抛出一个问题,其实所谓的熟悉原生JS,怎样的程度才是熟悉呢? 最近都在做原生JS熟悉的练习... 用原生Js封装了一个Ajax插件,引入一般的项目,传传数据,感觉还是可行的...简单说说思路,如有不正 ...

  2. 常用原生JS方法总结(兼容性写法)

    经常会用到原生JS来写前端...但是原生JS的一些方法在适应各个浏览器的时候写法有的也不怎么一样的... 今天下班有点累... 就来总结一下简单的东西吧…… 备注:一下的方法都是包裹在一个EventU ...

  3. 原生JS实现&quot;旋转木马&quot;效果的图片轮播插件

    一.写在最前面 最近都忙一些杂七杂八的事情,复习软考.研读经典...好像都好久没写过博客了... 我自己写过三个图片轮播,一个是简单的原生JS实现的,没有什么动画效果的,一个是结合JQuery实现的, ...

  4. 再谈React.js实现原生js拖拽效果

    前几天写的那个拖拽,自己留下的疑问...这次在热心博友的提示下又修正了一些小小的bug,也加了拖拽的边缘检测部分...就再聊聊拖拽吧 一.不要直接操作dom元素 react中使用了虚拟dom的概念,目 ...

  5. React.js实现原生js拖拽效果及思考

    一.起因&思路 不知不觉,已经好几天没写博客了...近来除了研究React,还做了公司官网... 一直想写一个原生js拖拽效果,又加上近来学react学得比较嗨.所以就用react来实现这个拖 ...

  6. 原生js实现autocomplete插件

    在实际的项目中,能用别人写好的插件实现相关功能是最好不过,为了节约时间成本,因为有的项目比较紧急,没充分时间让你自己来写,即便写了,你还要花大量时间调试兼容性.但是出于学习的目的,你可以利用闲暇时间, ...

  7. 原生js封装ajax:传json,str,excel文件上传表单提交

    由于项目中需要在提交ajax前设置header信息,jquery的ajax实现不了,我们自己封装几个常用的ajax方法. jQuery的ajax普通封装 var ajaxFn = function(u ...

  8. 原生JS实现购物车结算功能代码+zepto版

    html <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3 ...

  9. 原生js焦点轮播图

    原生js焦点轮播图主要注意这几点: 1.前后按钮实现切换,同时注意辅助图2.中间的button随着前后按钮对应切换,同时按button也能跳转到相应的index3.间隔调用与无限轮播.4.注意在动画时 ...

  10. 原生js移动端touch事件实现上拉加载更多

    大家都知道jQuery里没有touch事件,所以在移动端使用原生js实现上拉加载效果还是很不错的,闲话不多说,代码如下: //获取要操作的元素 var objSection = document.ge ...

随机推荐

  1. linux命令详解:md5sum命令

    前言 在网络传输.设备之间转存.复制大文件等时,可能会出现传输前后数据不一致的情况.这种情况在网络这种相对更不稳定的环境中,容易出现.那么校验文件的完整性,也是势在必行的. 使用说明 md5sum命令 ...

  2. Arduino101学习笔记(十四)&mdash;&mdash; Flash库

    一.一些API 1.打开文件 SerialFlashFile file; file = SerialFlash.open("filename.bin"); if (file) { ...

  3. 实验验证redis的快照和AOF

    安装配置redis http://www.cnblogs.com/myrunning/p/4222385.html 验证redis的主从复制 http://www.cnblogs.com/myrunn ...

  4. UVA 11090 Going in Cycle!!

    要求给定的图的中平均权值最小的环,注意处理自环的情况就能过了. 按照w1+w2+w3+….wn < n*ave的不等式,也就是(w1-ave) + (w2-ave) +…..(wn-ave) & ...

  5. MySQL简单查询

    1.普通查询 select * from info; #查询所有内容 select Code,Name from Info #查询某几列 2.条件查询 select * from Info where ...

  6. 20190228 搭建Hadoop基础环境

    下载VMware 12 版本以上 下载CentOS 7以上版本 安装虚拟机,安装系统时,注意设置root 账号和密码 虚拟机配置网络,命令ip addr 查看IP 地址,(配置网络网上有很多办法,百度 ...

  7. Spring是如何处理注解的

    如果你看到了注解,那么一定有什么代码在什么地方处理了它. Alan Hohn 我教Java课程时强调的一点是注解是惰性的.换句话说,它们只是标记,可能具有某些属性,但没有自己的行为.因此,每当你在一段 ...

  8. ECR是什么意思

    有效客户反应简称为ECR(efficient consumer response).它是1992年从美国的食品杂货业发展起来的一种供应链管理战略.这是一种分销商与供应商为消除系统中不必要的成本和费用并 ...

  9. 记2013年度成都MVP社区巡讲

    上个周六在天府软件园A区的翼起来咖啡举行了MVP社区巡讲成都站的活动,这个巡讲活动去年也搞过一次. MVP社区巡讲是 @微软中国MVP项目组 支持的,由各地的MVP担任讲师,给本地技术社区提供的一种社 ...

  10. Codeforces 888E - Maximum Subsequence(折半枚举(meet-in-the-middle))

    888E - Maximum Subsequence 思路:折半枚举. 代码: #include<bits/stdc++.h> using namespace std; #define l ...