javascript基础总结(二)

垃圾收集机制

参考javascript高级程序设计和博客谈谈JS垃圾回收机制

JavaScript引擎中有一个后台进程称为垃圾回收器,它监视所有对象,并删除那些不可访问的对象。
设置为null解除引用:

var user = { a: 1 };
user = null; // 这样就切断变量和对象的联系,可以被释放
  • 垃圾:
    一般来说没有被引用的对象就是垃圾,就是要被清除。如果几个对象引用形成一个环,互相引用,但根访问不到它们,这几个对象也是垃圾,要被清除。
    垃圾回收方法:

  • 标记清除:
    JavaScript中最重用的垃圾收集方式是标记清除。
    当运行一个函数的时候,就是当变量进入环境时,就将这个变量标记为“进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到它们。而当变量离开环境时,则将其标记为“离开环境”。

    首先,垃圾收集器在运行的时候会给存储在内存中的所有变量都加上标记。(即认为所有对象都是要清除的)
    然后,它会去掉环境中的变量(比如函数内的局部变量)以及被环境中的变量引用的变量的标记。剩下的就是没有在使用的对象,可以被垃圾回收了。
    在此之后,再被加上标记的变量将被视为准备删除的变量。
    最后,垃圾收集器完成内存清除工作,销毁那些带标记的值并回收它们所占用的内存空间。

  • 引用计数
    记录每个对象被引用的次数,每次新建对象、赋值引用和删除引用的同时更新计数器,如果计数器值为0则直接回收内存。
    优点:可即刻回收垃圾
    缺点:计数器的增减处理繁重;循环引用无法回收

var fn1 = {
  name: 'Dell'
};// 标记为1
var fn2 = fn1; // 标记为2
fn1 = {}; // 标记为2-1=1
fn2 = {}; // 标记为1-1=0,fn1可以被回收了

极端的情况:
循环引用

function fn(){
  var a = {};
  var b = {};
  a.sub = b; // a指向的对象标记为2
  b.sub = a; // b指向的对象标记为2
}
fn();
// 执行fn()之后,a、b指向的对象标记减1,并不为0,无法回收

假如这个函数被重复多次调用,就会导致大量内存得不到回收。为此放弃了引用计数方式,转而采用标记清除来实现其垃圾收集机制。可是,引用计数导致的麻烦依然存在。

IE 中有一部分对象并不是原生JavaScript对象。例如,其 BOM和DOM中的对象就是使用 C++以 COM(Component Object Model,组件对象模型)对象的形式实现的,而 COM对象的垃圾 收集机制采用的就是引用计数策略。

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

由于存在这个循环引用,即使将DOM元素(element)从页面中移除,由于myObject.element指向它,它不会被回收。
为了避免类似这样的循环引用问题,最好是在不使用它们的时候手工断开原生JavaScript对象与DOM元素之间的连接:

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

为了解决上述问题,IE9把BOM和DOM对象都转换成了真正的 JavaScript对象。

闭包

闭包是指有权访问另一个函数作用域中的变量的函数。常见的创建闭包方式,就是在一个函数内部创建另一个函数。

// 闭包
function add(y,z){
    var x = 1;  // 局部变量
    var add2 = function(){
        console.log(x+y+z);
    }
    return add2();
}
// 核心是add2()函数不接受参数,它使用的值是从执行环境中获取的
add(2,3); // 6

优点:有利于封装,可以访问局部变量。
缺点:容易产生内存泄漏。

关键词
function Preson(){
  this.name = "Nicholas";
  this.age = 29;
  this.job = "Software Engineer";
}
var person1 = new Person();

1.instanceof

console.log(person1 instanceof Person);// true
console.log(person1 instanceof Object);// true
// 所有对象本质上都是继承于Object

2.delete

delete person1.job;

用于删除对象的属性,但是对方法不起作用;不能删除原型链中的属性和变量;不能删除变量
3.call、apply
每个函数都包含两个非继承而来的方法:apply()和call()。这两个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内this对象的值。
apply()方法接收两个参数:在其中运行函数的作用域,参数数组。
call()方法与apply()方法的作用相同,区别仅在于接收参数的方式不同,在使用call()方法时,传递给函数的参数必须逐个列举出来。

function add(x,y){
    console.log(x+y);
}
function sub(x,y){
    console.log(x-y);
}
sub.apply(add,[2,1]); // 1   add调用sub
sub.call(add,2,1);    // 1   add调用sub

4.arguments
arguments是一个类数组对象,包含着传入函数中的所有参数,主要用途是保存函数参数。在函数代码中,使用特殊对象arguments,无需明确指出参数名就能访问它们。

function arg(x,y,z){
    console.log(arguments[0],arguments[1],arguments[2]);
    console.log(arguments.length);
}
arg(1,2,3); 
// 1 2 3
// 3

arguments.length:arguments的一个属性,指向传递给当前函数的参数数量。
argumentns.callee:arguments的一个属性,是一个指向当前执行的函数的指针。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值