1,垃圾回收机制
2种,标记清除,引用计数
2,DOM节点
整个文档是一个Document节点,
每个HTML标签是个元素Element节点,
每一个HTML属性是Attribute节点,
包含在HTML元素中的文本是Text节点
3,script标签中defer,和async
defer属性规定是否延迟执行脚本,直到页面加载为止,并行加载JS文件,按照Script标签的顺序执行;
async属性规定脚本一旦可用,异步执行,并行加载JS文件,下载完成立即执行,不会按照script标签的顺序执行;
4,闭包
闭包,是JavaScript两个核心技术之一(异步和闭包)。
闭包就是能够读取其他函数内部变量的函数。
由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"。
所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。
需要注意,函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明了一个全局变量!
1、闭包可以访问当前函数以外的变量
function getOuter(){
var date = '815';
function getDate(str){
console.log(str + date); //访问外部的date
}
return getDate('今天是:'); //"今天是:815"
}
getOuter();
getDate是一个闭包,该函数执行时,会形成一个作用域A,A中并没有定义变量date,但它能在父一级作用域中找到该变量的定义。
2、即使外部函数已经返回,闭包仍能访问外部函数定义的变量
function getOuter(){
var date = '815';
function getDate(str){
console.log(str + date); //访问外部的date
}
return getDate; //外部函数返回
}
var today = getOuter();
today('今天是:'); //"今天是:815"
today('明天不是:'); //"明天不是:815"
3、闭包可以更新外部变量的值
function updateCount(){
var count = 0;
function getCount(val){
count = val;
console.log(count);
}
return getCount; //外部函数返回
}
var count = updateCount();
count(815); //815
count(816); //816
使用闭包的注意点
1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。
闭包的作用
闭包可以用在许多地方,的最大用处有两个,一个是可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。
函数对象可以通过作用域关联起来,函数体内的变量都可以保存在函数作用域内,这在计算机科学文献中称为“闭包”。
所有的javascirpt函数都是闭包。
闭包的原理可不可以说一下?
当代码在一个环境中执行时,会创建变量对象的一个作用域链。用数据格式表达作用域链的结构如下。
[{当前环境的变量对象},{外层变量对象},{外层的外层的变量对象}, {window全局变量对象}] 每个数组单元就是作用域链的一块
,这个块就是我们的变量对象。
为毛闭包就能访问外部函数的变量呢?Javascript中的作用域链。
Javascript中有一个执行环境(execution context)的概念,它定义了变量或函数有权访问的其它数据,决定了他们各自的行为。每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中。
变量对象也是有父作用域的。当访问一个变量时,解释器会首先在当前作用域查找标示符,如果没有找到,就去父作用域找,直到找到该变量的标示符或者不再存在父作用域了,最终根据调用环境产生的环境栈来形成了一个由变量对象组成的作用域链,当一个环境没有被js正常垃圾回收时,我们依然可以通过引用来访问它原始的作用域链。
闭包和你刚刚说的作用域链有什么关系?
函数对象可以通过作用域关联起来,函数体内的变量都可以保存在函数作用域内,这在计算机科学文献中称为“闭包”。
作用域链其实就是引用了当前执行环境的变量对象的指针列表,它只是引用,但不是包含。因为它的形状像链条,它的执行过程也非常符合,所以我们都称之为作用域链。
5,undefined,null区别
- undefined未定义,缺少值
- null没有对象,此处不应该有值
6,延迟加载
7,call,apply
8,JS对象的创建形式
9,延迟脚本的方法和作用
10,||和&&逻辑运算符
皆从左至右运算,X||Y 先计算X并将其表达为布尔值,如果布尔值为true,则直接返回true(1),否则在计算Y将其表达为布尔值
X&&Y表达式中,先计算X将其表达为布尔值,如果布尔值为false,则返回false(0),否则继续计算Y。有趣的地方为当一个表达式为true,则返回表达式本身,也就是为什么1&&2 ,返回2而不是true或1。
11,一些细节
1,当设置对象属性时,js会隐式的将[]内的变量转化为字符串,如果是对象则都是[object Object]。
2,
12,apply 和 call 的区别
ECMAScript 规范给所有函数都定义了 call 与 apply 两个方法,它们的应用非常广泛,它们的作用也是一模一样,只是传参的形式有区别而已。
apply( )
apply 方法传入两个参数:一个是作为函数上下文的对象,另外一个是作为函数参数所组成的数组。
var obj = {
name : 'linxin'
}
function func(firstName, lastName){
console.log(firstName + ' ' + this.name + ' ' + lastName);
}
func.apply(obj, ['A', 'B']); // A linxin B
可以看到,obj 是作为函数上下文的对象,函数 func 中 this 指向了 obj 这个对象。参数 A 和 B 是放在数组中传入 func 函数,分别对应 func 参数的列表元素。
call( )
call 方法第一个参数也是作为函数上下文的对象,但是后面传入的是一个参数列表,而不是单个数组。
var obj = {
name: 'linxin'
}
function func(firstName, lastName) {
console.log(firstName + ' ' + this.name + ' ' + lastName);
}
func.call(obj, 'C', 'D'); // C linxin D
对比 apply 我们可以看到区别,C 和 D 是作为单独的参数传给 func 函数,而不是放到数组中。
对于什么时候该用什么方法,其实不用纠结。如果你的参数本来就存在一个数组中,那自然就用 apply,如果参数比较散乱相互之间没什么关联,就用 call。