一、内存空间
JS中每个数据都需要内存空间来存储,内存空间分对堆内存(stock)和栈内存(head)
- JS中的基本数据类型有固定的值大小保存在栈内存中
- JS中的引用数据类型大小值不固定,一般保存在堆内存中,JS不允许我们直接访问堆内存的位置,当我们访问引用数据类型的时候,实际是访问栈内存中保存的堆内存的引用地址
demo1:
var a = 12;
var b = true;
var c = 'abcd';
var d = {a:1}
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNvwVZ2x2bzNXak9CX90TQNNkRrFlQKBTSvwFbslmZvwFMwQzLcVmepNHdu9mZvwFVywUNMZTY18CX052bm9CX9gzViRnVHJmZKhFZ2plMMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2LcRHelR3LcJzLctmch1mclRXY39DNxIDN1ADNyITOxYDM4EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
demo2:
var a = 12;
var b = true;
var c = 'abcd';
var d = {a:1}
var e = c;
var f = d;
当var e = c; 复制基础数据类型时候会为新的变量赋值一个新值,虽然var e = c; 都是'abcd',但是e和c是两个相互不影响的新值
当var e = d; 复制引用数据类型的时候统一为了新的变量赋予新值,不同的是这个新值只是引用类型的地址指针,尽管相互独立。但是在堆内存中访问的数据仍然是同一个
实际应用中:要注意深拷贝和浅拷贝。
二、变量提升
- 函数及变量的声明都将被提升到函数的最顶部。
- 变量只有声明提升了,赋值不提升
- 函数内不声明直接使用的变量,创建的变量会按照作用域来查询来赋值
三、作用域
概念:
执行环境定义了变量或者函数有权访问其他数据。每个执行环境都有与之相关的变量对象。环境中所定义的所有变量和函数都保存在这个变量对象中,代码无法访问,但是解析器在解析的时候会使用它
关键字:
作用域链:词法语法分析、生成代码,代码执行
- 每个函数都有自己的执行环境,当执行流入一个函数的时候,函数的环境就会被推入一个环境栈中,当函数执行之后,栈将其环境弹出,把控制权返回之前的执行环境
- 当代码在一个环境中执行的时候,会创建变量对象的一个作用域链
- 作用域链中的变量对象来自外部环境中。下一个变量对象来自一个环境,一直延伸到全局环境
- 标识符的解析是沿着作用域链一级级搜索标识符的过程,逐级向后回溯知道找到标识符的位置
- 保证对作用域链中所有变量和函数的有序访问
- 函数的作用域在创建的时候就获得了
- scope是函数的一个内部属性,他是所有父级变量对象的层级链
- 内层Scope可以访问外层Scope的变量
var a = 10;
function testScope(arg) {
var a = 10;
function ab() {
a = 20;
var c = 2;
console.log(a);
}
ab();
console.dir(ab);
console.dir(testScope);
console.log(a);
};
testScope('hi');
console.log(a);
四、this指向
- Global context全局上下文中 指向window
- simple call 独立调用 指向window
- function context this由函数怎么调用实现
- arrow function 由词法或者静态作用域设置
- As an Object method 当作为函数方法调用的时候 指向函数本身
- 构造函数 new 方法中 指向被constructed 的新对象
- call apply 指向运行时的this
- bind 创建新函数 函数体和作用域和之前一样 但是 this 被永久绑定到传入的this中
- As a Dom event handler this为触发事件的dom元素
闭包:就是函数和函数声明时候作用域的组合
做几道题来加深理解
var name = 'window';
var example1 = {
name:'test',
say1:()=>{
console.log(this.name);
},
say2:()=>{
return () =>{
console.log(this.name);
}
},
say3:()=>{
return function(){
console.log(this.name);
}
},
say4:function () {
console.log(this.name);
},
say5:function(){
return function(){
console.log(this.name);
}
},
say6:function(){
return () =>{console.log(this.name)};
},
}
example1.say1();
example1.say2()();
example1.say3()();
example1.say4();
example1.say5()();
example1.say6()();
//
function sayBye(){
console.log(this.name);
}
sayNo = () =>{
console.log(this.name);
}
var testObj = {
name:'testObj',
}
testObj.sayBye = sayBye;
testObj.sayNo = sayNo;
testObj.sayBye();
testObj.sayNo();
example1.say1.call(testObj);
example1.say1.apply(testObj);
example1.say4.call(testObj);
example1.say4.apply(testObj);
example1.say4.bind(testObj)();
example1.say1.bind(testObj)();
//
//window window window test window test
//testObj window window window testObj testObj testObj window