javascript 性能分析:数据访问

一.javascript 四种数据类型

    1  literal values 直接量:字符串,数字,布尔值,数组,函数,对象,正则表达式,具有特殊意义的空值,以及未定义

    2 variables 变量 使用var创建的存储数据值

    3  Array items 数组项 具有数字索引 存储一个js数组对象

    4 object members 对象成员 具有字符串索引 存储一个js对象

     总的来说 直接量和局部变量要快于数组项和对象成员(但是有些浏览器对数组项和对象成员进行优化另外一回事)

二.管理作用域 

   每个javascript函数都被表示为对象或函数实例,拥有你可以编程访问的属性和一些不能被程序访问,仅供javascript引擎使用的内部属性 像[Scope] 包含一个函数被创建的作用域中对象的集合。这集合被称为函数的作用域链,它决定那些数据可由函数访问,函数作用域链中的每个对象称为一个可变对象,每个可变对象都以 健的形式存在。当一个函数创建后,它的作用域链被填充以对象,这些对象代表创建这函数的环境中可访问的数据。

     function add(num1, num2){
       var sum = num1 + num2;
      return sum;
    }

    当add函数创建后 它的作用域链中填入一个单独的可变对象 这全局对象代表了所有全局范围定义的变量。像窗口,浏览器和文档之类的访问接口都是全局变量。

  运行add函数时建立一个内部对象,称作 ‘运行期上下文’ (定义了一个函数运行的环境) 对函数的每次运行而言,每个 ‘运行期上下文’都是独立的 所以多次调用同一个函数就会导致多次的创建运行期上下文 函数执行完毕就会销毁。

  一个运行期上下文有它自己的作用域链 用于标识符解析。当运行期上下文被创建时,它的作用域链被初始化,连同运行函数的scope属性中的包含的对象 按照出现在函数的顺序复制到运行期上下文的作用域链中。然后被称作“激活对象”的新对象就为运行期上下文创建好了。 激活对象作为函数执行期的一个可变对象 包含访问所有局部变量 ,命名参数,参数集合 和this的接口。然后这对象被推人作用域链的前端。

   标识符识别过程决定从那里获取存储数据。这过程搜索运行期上下文的作用域链,查找同名的标识符。搜索工作从运行函数的激活目标的作用域链的前端开始。所以一个标识符处的位置越深  它的读写速度就越慢

   这样:用局部变量存储本地变量之外的变量值,如果它们在函数中的使用多于一次

     function initUI(){
      var bd = document.body,
      links = document.getElementsByTagName_r("a"),
      i = 0,
      len = links.length;
     while(i < len){
       update(links[i++]);
      }
      document.getElementById("go-btn").onclick = function(){
      start();
      };
      bd.className = "active";
     }

 改写:

     function initUI(){
      var doc = document,
      bd = doc.body,

       links = doc.getElementsByTagName_r("a"),

       i = 0,
      len = links.length;
      while(i < len){
        update(links[i++]);
      }
         doc.getElementById("go-btn").onclick = function(){
         start();
         };
         bd.className = "active";
       }

改变作用域:2种运行期间临时改变运行期作用域链 

    1.with表达式(避免写重复代码)

    function initUI(){
       with (document){ //avoid!
       var bd = body,
        links = getElementsByTagName_r("a"),
         i = 0,
        len = links.length;
       while(i < len){
          update(links[i++]);
        }
       getElementById("go-btn").onclick = function(){
        start();
       };
       bd.className = "active";
    }
    }

  运行with代码块的时候 一个新的可变对象将被创建 它包含指定对象的所有属性。这对象被插入到作用域链的前端,同时意味着函数的所有局部变量都被推人到第二个作用域链对象中。访问的代价更高了。

   2.try-catch表达式有相同的效果,将异常对象插入到作用域链的前端,函数的所有局部变量都被推人到第二个作用域链对象中。建议这样写:

   try {
       methodThatMightCauseAnError();
      } catch (ex){
       handleError(ex); //delegate to handler method
      }

  动态作用域:

    无论是with表达式还是try-catch表达式 以及包含()的函数 都被称为动态作用域。动态作用域因为运行代码而产生的 而静态分析不了

function execute(code) {
(code);
function subroutine(){
return window;
}
var w = subroutine();
//what value is w?
};

execute("var window = {};")  分析一下 w是全局变量 还是局部变量

 所以没有必要不推荐使用动态作用域。

 闭包,作用域,内存

 闭包 允许访问局部范围之外的数据。

function assignEvents(){
var id = "xdi9592";
document.getElementById("save-btn").onclick = function(event){
saveDocument(id);
};
}

由于闭包的scope属性包含与运行期上下文作用域链相同的对象引用 会产生副作用。通常一个函数的激活对象与运行期上下文一同销毁。但涉及闭包时 激活对象就无法销毁了。因为他的引用仍然存在闭包的scope属性中。这样就需要更多的内存开销,可能导致内存泄漏。

对象成员(文档对象模型和浏览器对象模型)

   prototype 原形 为所有给定类型的对象实例所共享。

var book = {
title: "High Performance JavaScript",
publisher: "Yahoo! Press"
};
alert(book.hasOwnProperty("title")); //true
alert(book.hasOwnProperty("toString")); //false
alert("title" in book); //true
alert("toString" in book); //true

原形链 prototype Chains

function Book(title, publisher){
this.title = title;
this.publisher = publisher;
}
Book.prototype.sayTitle = function(){
alert(this.title);
};
var book1 = new Book("High Performance JavaScript", "Yahoo! Press");
var book2 = new Book("JavaScript: The Good Parts", "Yahoo! Press");
alert(book1 instanceof Book); //true
alert(book1 instanceof Object); //true
book1.sayTitle(); //"High Performance JavaScript"
alert(book1.toString()); //"[object Object]"

 2个book实例共享同一个原形链,当book1.toString()被调用时 搜索工作必须深入原形链才能找到对象成员的 toString

深入的原形链越深 搜索的速度就会越慢。

嵌套变量

成员嵌套越深 访问速度就越慢 location.href 快于window.location.href 快于window.location.href.toString()

缓存对象成员的值

function hasEitherClass(element, className1, className2){
return element.className == className1 || element.className == className2;
}

改成:

function hasEitherClass(element, className1, className2){
var currentClassName = element.className;
return currentClassName == className1 || currentClassName == className2;
}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值