资讯专栏INFORMATION COLUMN

《高性能javascript》随记 - Data Access

fai1017 / 3321人阅读

摘要:内部属性包含一个函数被创建的作用域中的对象的集合,此集合被称为函数的作用域链。当作用域链销毁时,激活对象一同被销毁。下图展示了函数运行期上下文的作用域和闭包由于闭包的属性包含与运行期上下文作用域链相同的对象引用,会产生副作用。

javascript按照数据存储位置的不同可分为以下四类:

直接量(字符串、数字、布尔型、Object、Array、Function、正则表达式、NULL以及undefined)。

变量。

数组项。

对象成员。

javascript对以上四个类型数据的访问速度依次减慢,也就是说,访问直接量的速度是最快的,而访问对象成员的消耗的时间是最多的。

管理作用域

理解作用域是理解javascript的关键。作用域对javascript有非常多的影响,从知道哪些变量可以被访问,到确定this的值。javascript作用域也关系到性能。

作用域链

每一个javascript函数都可以看作一个对象,进一步说,它是一个函数实例。函数对象和其他的对象一样,拥有可编程访问属性内部属性,其中[[Scope]]就一个典型的内部属性。
内部属性[[Scope]]包含一个函数被创建的作用域中的对象的集合,此集合被称为函数的作用域链。他决定那些数据可以用函数访问。此函数中的每个对象被称为可变对象。当一个函数被创建后,它的作用域链被填充以对象,这些对象代表创建此函数的环境可以访问的数据。例如下面这个全局函数:

function add(a,b) {
    var sum = a + b;
    return sum;
}

add()函数被创建后,它的作用域链被填入一个多带带的可变对象,此全局对象代表所有全局范围内定义点变量。当add()函数运行时,会创建一个“运行期上下文”。一个运行期上下文定义了一个函数运行时的环境,所以多次调用同一个函数会产生多个运行期上下文。当函数执行完毕,运行期上下文就会被销毁。
一个运行期上下文有它自己的作用域链,用于标识符解析。当运行期上下文被创建时,作用域链为初始化,连同运行函数的[[Scope]]属性中所包含的对象。这些值按照它们在函数中出现的顺序被复制到运行期上下文所在的作用域链中。这项工作一旦完成,一个称为“激活对象”的新对象就为运行期上下文准备好了。此激活对象是一个可变对象,包含访问所有局部变量、命名参数、参数集合,和this接口。然后此对象推入作用域链的前端。当作用域链销毁时,激活对象一同被销毁。下图展示了实例代码对应的运行期上下文:

在函数运行过程当中,每遇到一个变量,函数就从这个作用域链中依次进行查找,正是这种查找过程影响了性能。一个标识符所处的位置越深,读写它的速度就越慢。所以,当一个函数中,如果要频繁的调用一个全局变量,那么最好用一个局部变量把它保存下来。

闭包

闭包是javascript最强大的一面,它允许函数访问局部范围之外的数据。为了了解与闭包有关的性能问题,我们看下面的例子:

function assignEvents(){
    var id = "123";
    document.getElementById("savaBtn").onclick = function(e) {
    savaDocument(id);
    };
}

assignEvents()函数为一个DOM元素指定了一个时间处理函数。此事件处理函数就是一个闭包,在assignEvents()执行时创建,这个闭包可以访问其范围内部的id变量。下图展示了函数运行期上下文的作用域和闭包:

由于闭包的[[Scope]]属性包含与运行期上下文作用域链相同的对象引用,会产生副作用。通常,一个函数的激活对象与运行期上下文一同销毁。当涉及闭包时,激活对象就无法销毁了。这意味着,闭包与非闭包函数相比,需要消耗更多的内存。
当一个闭包被执行时,它的作用域链与[[Scope]]中引用的两个相同的作用域链同时被初始化,然后一个新的激活对象为闭包自身所创建。如下图所示:

注意闭包中使用的两个标识符:idsaveDocument,他们并不是在作用域链中的最前端,这就造成了数据读写的性能问题。

原型

javascript中的对象是基于原型的,原型是其他对想的基础,定义一个新的对象必须具有的成员。对象成员分为实例成员和原型成员,你可以通过hasOwnProperty()函数来确定某个成员是否为实例成员。要确定某个对象是否有某个属性,可以用in关键字来确定。

原型链

可以通过prototype属性来构造原型链,但是要注意的是:对象在查找成员的过程就像函数作用域链查找变量的过程类似,先查找实例成员,如果找不到再从原型成员中查找,所以也有类似的性能问题。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/87589.html

相关文章

  • 性能javascript随记 - Loading and Excecution

    摘要:此过程中,页面的解析与用户的交互都是阻塞的。非阻塞脚本延时脚本可以给标签添加一个属性,这个属性表明元素中的脚本不打算修改,因此代码可以稍后执行。此技术的重点在于无论在何处启动下载,脚本的下载和运行都不会阻塞页面的处理过程。 当浏览器遇到标签时,页面的加载、介些都会停下来,运行此javascript代码,然后再继续加载。这种事情同样会发生在那些以src属性调用的外部脚本,浏览器首先下载外...

    DevTTL 评论0 收藏0
  • 性能javascript随记 - DOM Scripting

    摘要:操作的代价非常昂贵,对元素节点的访问和修改样式布局的改变以及事件的绑定都影响着网页的性能。所以,尽量减少对布局信息的查询次数,并用局部变量参与计算。当动画结束时,重新定位,从而只一次下移文档其他元素的位置。这样可以最小化事件句柄数量。 DOM操作的代价非常昂贵,对元素节点的访问和修改、样式、布局的改变以及DOM事件的绑定都影响着网页的性能。 批量修改DOM 如果要对元素节...

    Ryan_Li 评论0 收藏0
  • JavaScript·摘抄·随记(持续补充中)

    摘要:无主题,内容为感触较深的一些答疑探讨等,摘自多篇文章,侵删为什么是单线程的单线程,与它的用途有关。作为浏览器脚本语言,的主要用途是与用户互动,以及操作。这决定了它只能是单线程,否则会带来很复杂的同步问题。摘自运行机制详解再谈作者阮一峰 无主题,内容为感触较深的一些答疑、探讨等,摘自多篇文章,侵删 1、为什么JavaScript是单线程 JavaScript的单线程,与它的用途有关。作...

    young.li 评论0 收藏0
  • JavaScript·随记 Null vs. Undefined

    摘要:刚学了一些的基础语法,试着用一下。相关文档基本语法配合基本使用相同点和都是的基本数据类型扩展的种基本数据类型和都是值扩展的种值空字符串不同点可见代表变量有值,值为空且该值是通过变量赋值获得的代表声明了变量,但没有为其赋值。 刚学了一些 Markdown 的基础语法,试着用一下。 相关文档:Markdown基本语法配合基本使用 相同点: null 和 undefined 都是js...

    Tychio 评论0 收藏0
  • JavaScript·随记 深拷贝 vs. 浅拷贝

    摘要:而在这个运算符的相关用例中,往往会涉及到其他知识点,深拷贝和浅拷贝就是其中之一。即对象的浅拷贝会对主对象的值进行拷贝,而该值有可能是一个指针,指向内存中的同一个对象。,可以看到深拷贝和浅拷贝是对复制引用类型变量而言的。 在ES6的系列文章中,基本都会提到Spread——扩展运算符(...)。而在这个运算符的相关用例中,往往会涉及到其他知识点,深拷贝和浅拷贝就是其中之一。 背景知识 在讨...

    RyanQ 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<