CHANX's Blog

vuePress-theme-reco CHANX    2019 - 2021
CHANX's Blog

Choose mode

  • dark
  • auto
  • light
主页
分类
  • 其他other
  • 前端front-end
  • 后端back-end
  • 笔记note
  • 随笔essay
标签
时间轴
关于我
每日AC
快速访问🎈
  • 洛谷 (opens new window)
  • Virtual Judge (opens new window)
  • LeetCode (opens new window)
  • Vue.js (opens new window)
  • Can I Use (opens new window)
  • Java SE API Documentation (opens new window)
  • Program Creek (opens new window)
  • Spring (opens new window)
  • Stackoverflow (opens new window)
  • Linux命令大全 (opens new window)
  • 编程语言排行榜 (opens new window)
GitHub (opens new window)
author-avatar

CHANX

38

Article

23

Tag

主页
分类
  • 其他other
  • 前端front-end
  • 后端back-end
  • 笔记note
  • 随笔essay
标签
时间轴
关于我
每日AC
快速访问🎈
  • 洛谷 (opens new window)
  • Virtual Judge (opens new window)
  • LeetCode (opens new window)
  • Vue.js (opens new window)
  • Can I Use (opens new window)
  • Java SE API Documentation (opens new window)
  • Program Creek (opens new window)
  • Spring (opens new window)
  • Stackoverflow (opens new window)
  • Linux命令大全 (opens new window)
  • 编程语言排行榜 (opens new window)
GitHub (opens new window)

JS重难点梳理

vuePress-theme-reco CHANX    2019 - 2021

JS重难点梳理

CHANX 2020-10-22 20:38:32 Javascript

# 第6章 面向对象的程序设计

# 理解对象

# 属性类型

# 定义多个属性

# 读取属性的特性

# 创建对象

# 工厂模式

# 构造函数模式

# 原型模式

# 组合使用构造函数模式和原型模式

# 动态原型模式

# 寄生构造函数模式

# 稳妥构造函数模式

# 继承

# 原型链

# 借用构造函数

# 组合继承

# 原型式继承

# 寄生式继承

# 寄生组合式继承

# 第7章 函数表达式

# 递归

# 闭包

闭包:函数中有权访问另一个函数作用域中的变量

# 闭包与变量

function createFunctions(){
	var result = new Array();
	for(var i = 0; i < 10; i++){
		result[i] = function(){
			return i;
		};
	}
	return result;
}
1
2
3
4
5
6
7
8
9

上述例子每个函数都引用着保存变量i的同一个变量对象,所以每一个函数内部i的值都是10

function createFunctions(){
	var result = new Array();
	for(var i = 0; i < 10; i++){
		result[i] = (function(num){
            return function(){
                return num;
            }
		})(i);
	}
	return result;
}
1
2
3
4
5
6
7
8
9
10
11

这个例子中我们没有直接把闭包赋值给数组,二十定义一个匿名函数并立即执行。由于函数参数式按值传递的,所以就会将变量i的当前值复制给参数num。而在这个匿名函数内部,又创建并返回了一个访问num的闭包。这样一来,result数组中的每个函数都有自己的num变量的一个副本,因此就可以返回各自不同的数值

# 关于this对象

var name = "The Window";

var object = {
	name : "My Object",
	getNameFunc: function(){
		return function(){
			return this.name;
		}
	}
};

alert(object.getNameFunc()());	//"The Window"(在非严格模式下)
1
2
3
4
5
6
7
8
9
10
11
12

每个函数在被调用的时候,其活动对象都会自动取得两个特殊变量:this和arguments。内部函数在搜索这两个变量时,只会搜索到其活动对象为止,因此永远不可能直接访问外部函数中的这两个变量

var name = "The Window";

var object = {
	name : "My Object",
	getNameFunc: function(){
        var _this = this;
		return function(){
			return _this.name;
		}
	}
};

alert(object.getNameFunc()());	//"My Object"
1
2
3
4
5
6
7
8
9
10
11
12
13

另外,在几种特殊情况下,this的值可能会意外地改变。

var name = "The Window";
var object = {
	name : "My Object",
	getName: function(){
		return this.name;
	}
};


object.getName();	//"My Object"
(object.getName)();	//"My Object"
(object.getName = object.getName)();	//"The Window",在非严格模式下
1
2
3
4
5
6
7
8
9
10
11
12

第一和第二行代码其实是一样的,第三行代码先执行赋值语句再调用赋值后的结果。因为这个赋值表达式的值是函数本身,所以this的值得不到维持。常见情况下并不会出现二三两种写法,只是为了更好地说明细微的语法变化可能会导致this的值发生改变。

# 内存泄漏

IE9之前的版本对JScript对象和COM对象使用不同的垃圾收集例程,因此闭包在IE的这些版本里会导致一些特殊问题。具体来说,如果闭包的作用域链中保存着一个HTML元素,那么就意味着该元素将会无法被销毁

function assignHandler(){
	var element = document.getElementById("someElement");
	element.onclick = function(){
		alert(element.id)
	};
}
1
2
3
4
5
6

以上代码创建了一个作为element元素事件处理程序的闭包,而这个闭包则又创建了一个循环引用。由于匿名函数保存了一个对assignHandler()的活动对象的引用,因此就会导致无法减少element的引用数。只要匿名函数存在,element的引用数至少也是1,因此它所占用的内存就永远不会被回收

function assignHandler(){
	var element = document.getElementById("someElement");
    var id = element.id;
	element.onclick = function(){
		alert(id)
	};
    element = null;
}
1
2
3
4
5
6
7
8

在上面的代码中,通过把element.id的一个副本保存在一个变量中,并且在闭包中引用该变量消除了循环引用。但仅仅做到这一步还是不能解决内存泄漏的问题。必须要记住:闭包会引用包含函数的整个活动对象,而其中包含着element。即使闭包不直接引用element,包含函数的活动对象中也仍然会保存一个引用。因此,有必要把element设置为null。这样就能接触对DOM对象的引用,顺利减少其因引用数,确保正常回收其占用的内存。

# 模仿块级作用域

在Javascript中没有块级作用域的概念(ES6中出现了let)

(function output(){
    for(var i = 0; i < 5; i++){
    	alert(i);
    }
    alert(i);	//"5"
})();
1
2
3
4
5
6

在Java、C++等语言中,变量i只会在for循环的语句中有定义,循环一旦结束,变量i就被销毁。

可是在Javascript中变量i是定义在output()的活动对象中的,因此从它有定义开始,就可以在函数内部的任意处访问它

匿名函数可以用来模仿块级作用域(又称私有作用域)并避免这个问题

function(){
	//这里是块级作用域
}();	//出错
1
2
3

Javascript将function关键字当作一个函数声明的开始,而函数声明后面不能跟圆括号。然而,函数表达式的后面可以跟圆括号

(function(){
	//这里是块级作用域
})();
1
2
3

无论在什么地方,要临时使用变量就可以使用私有作用域

function output(count){
    (function(){
        for(var i = 0; i < count; i++){
    		alert(i);
    	}
    })();
    alert(i);	//导致一个错误
}
1
2
3
4
5
6
7
8

在for循环的外部插入了一个私有作用域。在匿名函数中定义的任何变量都会在执行结束时被销毁,因此变量i只能在循环中使用。而在私有作用域中能够访问变量count,是因为这个匿名函数是一个闭包,它能够访问包含作用域内的所有变量

# 私有变量

# 静态私有变量

# 模块模式

# 增强的模块模式

# 小结

在 GitHub 上编辑此页! (opens new window)
上次更新时间: 11/21/2020, 7:38:58 PM