(一) 基本数据类型和引用数据类型的区别
基本数据类型和引用数据类型数据在内存中的存储
-
基本数据类型存放在 栈区
-
引用数据类型存放在 堆区, 同时在栈区存放数据,在堆区存放的地址(引用)
(二) 函数的调用方式
1.普通函数的调用, 函数名();
2.回调函数:
// 回调函数: 函数作为参数
// callback是个函数
function foo(callback) {
callback(100); // callback就是goo(100)
}
function goo(num) {
console.log(num);
}
foo(goo);
回调函数是一个作为变量传递给另外一个函数的函数,它在主体函数执行完之后执行。
function A有一个参数function B,function B会在function A执行完成之后被调用执行。
3.递归函数
// 递归是指函数自己调用自己
function say() {
say();
}
// 不使用for循环进行数字累加
var sum = 0;
function add(i) {
sum = sum + i;
console.log(sum);
++i;
if (i <= 100) {
add(i);
}
}
add(1);
4.自调函数
// 自调用:可以避免全局变量污染
(function(c){
var a = 100;
var b = 200;
console.log(c);
})(300);
(三) js垃圾回收机制#
垃圾回收机制是什么#
垃圾回收机制(GC:Garbage Collection),执行环境负责管理代码执行过程中使用的内存。垃圾收集器会定期(周期性)找出那些不在继续使用的变量,然后释放其内存。但是这个过程不是实时的,因为其开销比较大,所以垃圾回收器会按照固定的时间间隔周期性的执行。
垃圾回收策略是什么#
2种最为常用:标记清除和引用计数,其中标记清除更为常用。
标记清除(mark-and-sweep):是对于脱离作用域的变量进行回收,当进入作用域时,进行标记,离开作用域时,标记并回收这些变量。到目前为止,IE、Firefox、Opera、Chrome、Safari的js实现使用的都是标记清除的垃圾回收策略或类似的策略,只不过垃圾收集的时间间隔互不相同。 当变量进入环境(例如,在函数中声明一个变量)时,就将这个变量标记为“进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占的内存,因为只要执行流进入相应的环境,就可能用到它们。而当变量离开环境时,这将其 标记为“离开环境”。
引用计数:引用计数是跟踪记录每个值被引用的次数。就是变量的引用次数,被引用一次则加1,当这个引用计数为0时,被视为准备回收的对象,每当过一段时间开始垃圾回收的时候,就把被引用数为0的变量回收。引用计数方法可能导致循环引用,类似死锁,导致内存泄露。
如何减少垃圾回收开销#
由于每次的垃圾回收开销都相对较大,并且由于机制的一些不完善的地方,可能会导致内存泄露,我们可以利用一些方法减少垃圾回收,并且尽量避免循环引用。
-
在对象结束使用后 ,令obj = null。这样利于解除循环引用,使得无用变量及时被回收;
-
js中开辟空间的操作有new XX() 比如new Date() , [ ], { }, function (){..}。尽量减少此类操作, 最大限度的实现对象的重用;举例:
-
慎用闭包。闭包容易引起内存泄露。本来在函数返回之后,之前的空间都会被回收。但是由于闭包可能保存着函数内部变量的引用,且闭包在外部环境,就会导致函数内部的变量不能够销毁。
var arr = [1,2,3,4];
arr = []; // 清空数组-不好的做法
arr.length = 0; // 清空数组,好的做法
如何优化垃圾回收#
分代回收(Generation GC):与Java回收策略思想是一致的。目的是通过区分“临时”与“持久”对象;多回收“临时对象”区(young generation),少回收“持久对象”区(tenured generation),减少每次需遍历的对象,从而减少每次GC的耗时。 增量GC:这个方案的思想很简单,就是“每次处理一点,下次再处理一点,如此类推。
(四) js异步编程#
(1) 同步和异步(理解)#
js中的同步和异步跟生活中的同步异步意思有些不太一样
js的同步指的是,同一时间只执行一个任务, 当一个任务结束以后才能执行下一个任务。
js的异步指的是,同一时间可以执行多个任务,常见的js异步操作有setTimeout(), setInterval(), ajax请求等。
(2) 单线程和多线程(理解)#
单线程: 同一时间只能做一件事 多线程: 同一时间可以做多件事 JavaScript语言的一大特点就是单线程, 那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊。比如java和c#就是多线程的语言。 JavaScript的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准? 所以,为了避免复杂性,从一诞生,JavaScript就是单线程,这已经成了这门语言的核心特征,将来也不会改变。
(3) JS中的异步运行机制#
也称js事件循环机制(Event Loop)
JS是单线程的,那么他是如何是实现异步操作的? JS中的异步运行机制(背诵):
(1)所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
(2)主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件(事件一般都有对应的回调函数)。
(3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行任务(实际上就是执行任务对应的回调函数)。
(4)主线程不断重复上面的前三步。
(五) this的指向#
问题:谈谈this的指向(背诵) 或问:解释下JavaScript中this是如何工作
答: this的指向有以下几种情况
注意: this永远指向函数运行时所在的对象,而不是函数被创建时所在的对象。
- 普通的函数调用: 函数被谁调用,this就是谁。
- 匿名函数或不处于任何对象中的函数指向window 。
- 如果是call, apply, bind,this指向了这三者调用函数时传入的第一个参数
- 构造函数中的this, 直接调用函数this的指向同第1点, 使用new操作符, this指向构造函数所创建的实例对象
- 箭头函数的指向: 由于箭头函数不绑定this, 父级元素的this指向, 作为自己的this值
(1) 普通的函数调用#
函数被谁调用,this就是谁
<!DOCTYPE html>
<html lang="en">
<body>
<script>
function say() {
console.log('this:',this);
}
say(); // 实际是: window.say(), 所以this指向window
var person = {
name: '张三',
sayName: function() {
console.log('this',this);
}
}
person.sayName(); // person调用了sayName,
</script>
</body>
</html>
(2) 匿名函数或不处于任何对象中的函数指向window
var person = {
name: '张三',
say: function () {
setTimeout(function() {
console.log(this);
},1000);
}
}
person.say();
(3) call, apply, bind的指向