基础知识梳理

时间:2021-09-05 14:45:02

基础知识梳理:
1.apply、call、bind区别
都为了改变this指向
apply传值为数组
call传值为参数序列
apply 、 call 、bind 三者都是用来改变函数的this对象的指向的;
apply 、 call 、bind 三者第一个参数都是this要指向的对象,也就是想指定的上下文;
apply 、 call 、bind 三者都可以利用后续参数传参;
bind 是返回对应函数,便于稍后调用;apply 、call 则是立即调用 。
2.JavaScript的编译
//复制粘贴
JavaScript的编译

很多人说JavaScript是解释型或者动态语言,是不需要编译的。其实不然,JavaScript是需要编译的,其编译发生在代码执行前的一瞬间(几微妙或者更短的时间内)。大多数编译型的语言编译大致都可以分3个步骤:分词,解析,生成代码。JavaScript也不例外,但是JavaScript会有更复杂的过程。
分词

大家知道,其实我们99.99%的代码都是文本类型。也就是说编译器拿到的是一堆实现约定好格式的文本,编译器拿到文本要干的第一件事情就是分词(也可以叫做词法分析)。就拿赋值语句来说(var a = 0;),编译器经过分词之后就会拿到这样的结果:var、a、=、0。
解析

经过词法分析,编译器在拿到分词结果之后便会根据分词的结果生成一个叫做“抽象语法树”(Abstract Syntax Tree)的树形结构,简称AST。就拿(var a = 0;)来说,树结构下一般会有以下节点:存储a的名称(也就是“a”)、a的类型、a的值。
生成代码

在这阶段,编译器根据生成的“抽象语法树”来生成计算机可以识别的指令。在从JavaScript到机器指令之间,JavaScript引擎还做了很多事情,以var a = 0;为例: 其实这条语句,JavaScript编译器会分为2个步骤执行(感谢TylerPeng的提醒):
var a;此时,JavaScript引擎会询问当前作用域中是否已经申明了a变量,如果a已经申明,那么编译器会忽略此次申明;如果没有找到a的身影,那么编译器会在当前作用域中申明一个a变量。
a = 0;赋值时,询问当前作用域中是否已经申明了a变量,如果没有则询问当前作用域的上级(此过程与我在JavaScript之闭包一文中类似)。如果最终没有找到a,那么就会报错;如果找到了a,那么就会直接使用。
其他的事

其实JavaScript引擎除了基本的3个编译步骤,还做了很多其他的事情,例如:代码优化、整理等。
变量申明提升

既然已经讲到了这里,也不得不提到这个概念。其实在JavaScript中,变量申明是会被提升到当前作用域的最顶部,思考一下代码:

function foo(){
console.log(a);
var a = 3;
}
foo(); // undefined

但是按照编译规则,在执行到console.log(a)时,代码应该会报错才对,现在为什么又打印出“undefined”呢,打印出“undefined”很显然变量已经被申明了。上面我有提到,JavaScript引擎会对我们的代码进行优化、整理,真正编译器拿到的代码是这个样子的:

function foo(){
var a;
console.log(a);
a = 3;
}
foo(); // undefined

就像我们上面说到的一样,申明赋值这个操作,JavaScript会分成2个步骤完成:申明和赋值。 其实不止变量申明的提升,函数的申明也会提升,思考一下代码:

foo(); // 3
function foo(){
var a = 3;
console.log(a);
}

我们在调用foo时,foo函数还没有申明。但是我们居然能得到我们所期望的值,这说明函数也会提升。
总结

了解了JavaScript的编译规则,应该对它会有不同的认识。其实JavaScript是一门被精心设计的语言,其优势不言而喻。当今有很多人吐槽JavaScript,吐槽JavaScript各种令人讨厌的坑。其实学习和工作哪个不是不断的在填自己知识上填坑呢?
//复制粘贴结束
(出处为https://swfbarhr.gitbooks.io/erblog/content/compile.html
3.new到底都做了什么

var o = new Object();
o.[[Prototype]] = Foo.prototype;
Foo.call(o);

声明一个新的对象,将实例化的类圆形指向空对象,将原类this指向到新对象,完成整个过程。
4.基本数据类型和复杂数据类型存的位置
简单数据类型:它们值在占据了内存中固定大小的空间,并被保存在内存中:

var a = 1;
var b = a;

上面代码中a就是简单数据类型(Number),b就是a的副本,它们两者都占有不同位置但相等的内存空间
复杂数据类型:复杂的数据类型即引用类型,它的值是对象,保存在内存中,包含引用类型值的变量实际上包含的并不是对象本身,而是一个指向该对象的指针,从一个变量向另一个变量复制引用类型的值,复制的其实是指针,因此两个变量最终都指向同一个对象。
5.深度拷贝递归

function deepCopy(source) {
var result = {};
for(var key in source) {
if(typeof source[key] === 'object') {
result[key] = deepCopy(source[key])
} else {
result[key] = source[key]
}
}
return result;
}

6.localStoage可以用来保持同一域名下的通信

window.addEventListener('storage',function(e){console.log(e)});