JS重难点梳理
本文最后更新于:几秒前
第6章 面向对象的程序设计
理解对象
属性类型
定义多个属性
读取属性的特性
创建对象
工厂模式
构造函数模式
原型模式
组合使用构造函数模式和原型模式
动态原型模式
寄生构造函数模式
稳妥构造函数模式
继承
原型链
借用构造函数
组合继承
原型式继承
寄生式继承
寄生组合式继承
第7章 函数表达式
递归
闭包
闭包:函数中有权访问另一个函数作用域中的变量
闭包与变量
1 |
|
上述例子每个函数都引用着保存变量i的同一个变量对象,所以每一个函数内部i的值都是10
1 |
|
这个例子中我们没有直接把闭包赋值给数组,二十定义一个匿名函数并立即执行。由于函数参数式按值传递的,所以就会将变量i的当前值复制给参数num。而在这个匿名函数内部,又创建并返回了一个访问num的闭包。这样一来,result数组中的每个函数都有自己的num变量的一个副本,因此就可以返回各自不同的数值
关于this对象
1 |
|
每个函数在被调用的时候,其活动对象都会自动取得两个特殊变量:this和arguments。内部函数在搜索这两个变量时,只会搜索到其活动对象为止,因此永远不可能直接访问外部函数中的这两个变量
1 |
|
另外,在几种特殊情况下,this的值可能会意外地改变。
1 |
|
第一和第二行代码其实是一样的,第三行代码先执行赋值语句再调用赋值后的结果。因为这个赋值表达式的值是函数本身,所以this的值得不到维持。常见情况下并不会出现二三两种写法,只是为了更好地说明细微的语法变化可能会导致this的值发生改变。
内存泄漏
IE9
之前的版本对JScript
对象和COM
对象使用不同的垃圾收集例程,因此闭包在IE的这些版本里会导致一些特殊问题。具体来说,如果闭包的作用域链中保存着一个HTML
元素,那么就意味着该元素将会无法被销毁
1 |
|
以上代码创建了一个作为element
元素事件处理程序的闭包,而这个闭包则又创建了一个循环引用。由于匿名函数保存了一个对assignHandler()
的活动对象的引用,因此就会导致无法减少element的引用数。只要匿名函数存在,element
的引用数至少也是1,因此它所占用的内存就永远不会被回收
1 |
|
在上面的代码中,通过把element.id
的一个副本保存在一个变量中,并且在闭包中引用该变量消除了循环引用。但仅仅做到这一步还是不能解决内存泄漏的问题。必须要记住:闭包会引用包含函数的整个活动对象,而其中包含着element
。即使闭包不直接引用element
,包含函数的活动对象中也仍然会保存一个引用。因此,有必要把element
设置为null
。这样就能接触对DOM
对象的引用,顺利减少其因引用数,确保正常回收其占用的内存。
模仿块级作用域
在Javascript中没有块级作用域的概念(ES6中出现了let
)
1 |
|
在Java、C++等语言中,变量i只会在for循环的语句中有定义,循环一旦结束,变量i就被销毁。
可是在Javascript中变量i是定义在output()
的活动对象中的,因此从它有定义开始,就可以在函数内部的任意处访问它
匿名函数可以用来模仿块级作用域(又称私有作用域)并避免这个问题
1 |
|
Javascript将function关键字当作一个函数声明的开始,而函数声明后面不能跟圆括号。然而,函数表达式的后面可以跟圆括号
1 |
|
无论在什么地方,要临时使用变量就可以使用私有作用域
1 |
|
在for循环的外部插入了一个私有作用域。在匿名函数中定义的任何变量都会在执行结束时被销毁,因此变量i只能在循环中使用。而在私有作用域中能够访问变量count,是因为这个匿名函数是一个闭包,它能够访问包含作用域内的所有变量