
课程咨询: 400-996-5531 / 投诉建议: 400-111-8989
认真做教育 专心促就业
代码执行效率对于系统运行速度还是有很大的影响作用的,今天我们就通过案例分析来了解一下,提高js函数的执行效率的常用方法都有哪些。
1、作用域链和标识符解析
每一个JS 函数都表示为一个对象,该对象有一个内部属性[[Scope]],它包含了一个函数被创建的作用域中对象的集合,这个集合被称为函数的作用域链(Scope chain),它决定哪些数据能被函数访问。函数作用域中的每个对象被称为一个可变对象(variable object)。当一个函数创建后,它的作用域链会被创建此函数的作用域中可访问的数据对象所填充。
而执行此函数时则会创建一个称为"运行期上下文(execution context)"的内部对象,它定义了函数执行时的环境。函数每次执行时对应的运行期上下文都是独一无二的,所以多次调用同一个函数就会导致创建多个运行期上下文。当函数执行完毕,执行上下文就被销毁。
而我们刚刚讲的函数作用域链和这个运行期上下文有什么关系呢?是这样的,每个运行期上下文都有自己的作用域链,用于标识符解析,而它的作用域链引用的则是函数的内部对象[[Scope]] 所指向的作用域链。此外还会创建一个"活动对象(Activation object)",该对象包含了函数的所有局部变量、命名参数、参数集合以及this,当函数执行时它又被当作可变对象,和前面是一回事。然后此对象会被推入作用域链的前端,就这样运行期上下文也就创建好了,当运行期上下文被销毁,活动对象也随之销毁。
2、标识符解析的性能
标识符解析是有代价的,在运行期上下文的作用链中,一个标识符所在的位置越深,它的读写速度也就越慢,显然对局部变量的读写是快的,因为它所在的对象处于作用链的前端。一个好的经验法则是:如果某个跨作用域的值在函数中被引用一次以上,那么就把它存储到局部变量里。
此外代码执行时临时改变作用域链也会影响标识符解析的性能,有两个语句会造成这种情况——with 和catch,这两条语句被执行时都会将一个新的可变对象(with 的是语句中指定的对象、catch 的是异常对象)推入作用域链的头部,这样原有的可访问对象都被往后推了一个层次,这使得它们的访问代价更高了。因此对于with 语句好避免使用,catch 语句要用的话可以定义一函数来进行错误的处理以减少catch 内的语句数量。
3、对象成员解析、原型、原型链
对象成员指的是对象的属性或方法,当我们要访问TestObj.abc 这样一个对象成员时,先在标识符解析的过程中找到了TestObj 对象,接下来要访问abc 属性(或是方法)则要进行对象成员解析的过程了。
JavaScript 中的对象是基于原型的,原型是其他对象的基础,它定义并实现一个新对象必须包含的成员列表。对象通过一个内部属性__proto__(这个属性在Firefox、Safari 和Chrome 中对开发者可见) 绑定到它的原型。
对象可以有两种成员类型:实例成员和原型成员。实例成员存在于对象实例中,原型成员则由对象原型继承而来。一旦创建了一个内置对象(如Object 和Array) 的实例,它们就会自动拥有一个Object 实例作为原型
4、对象成员解析的性能
和标识符解析一样,对象成员的解析也是有开销的,原型链的遍历过程中,每深入一层都会增加性能的损失,于是对象在原型链中存在的位置越深,找到它就越慢。
另外由于对象成员可能包含其他成员,例如window.location.href,每次遇到点操作符,该嵌套成员都会导致JavaScript 引擎搜索所有对象成员,显然对象成员嵌套得越深,访问速度就会越慢,因此尽量少用,例如执行location.href 总是要比window.location.href 要快。
【免责声明】本文系本网编辑部分转载,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及作品内容、版权和其它问题,请在30日内与管理员联系,我们会予以更改或删除相关文章,以保证您的权益!