「这是我参与2022首次更文挑战的第22天,活动详情查看:2022首次更文挑战」
es5变量声明方式var存在两个问题:
- 变量提升,即变量不需要先声明后使用,也可先使用后声明。
- 变量的作用域只有两种:全局作用域和局部作用域。
let声明的变量作用域为块级作用域,且必须先声明后使用,使代码更加严谨。
看下面这题,输出结果应为多少?
var a = 10;
(function(){
console.log(a);
var a = 100;
})();
答案是undefined,因为var声明变量的提升效果,这里相当于:
(function(){
var a;
console.log(a);
a = 100;
})();
值得注意的是,JavaScript永远是先解析声明函数,再解析变量。
函数执行
目的:把之前创建函数在内存空间中存储的“代码字符串”变为真正的JS代码执行,从而实现相关的效果
- 第一步:首先形成一个私有的作用域(给接下来的代码执行提供一个私有的环境)
- 第二步:到私有作用域中依然要先进性词法解析
- 先给形参赋值
- 私有作用域中的变量提升
- 第三步:在私有作用域中把代码自上而下执行
堆栈内存
JS中有两大内存:堆内存(Heap)、栈内存(Stack) 堆内存作用:用来存储内容的(对象存储的是键值对,函数存储的是代码字符串) 栈内存作用:也可以被称为作用域,是代码解析和执行的环境
Symbol数据类型
ES5 的对象属性名都是字符串,这容易造成属性名的冲突。比如,你使用了一个他人提供的对象,但又想为这个对象添加新的方法(mixin 模式),新方法的名字就有可能与现有方法产生冲突。如果有一种机制,保证每个属性的名字都是独一无二的就好了,这样就从根本上防止属性名的冲突。这就是 ES6 引入Symbol的原因。
对变量或值调用 typeof 运算符将返回下列值之一:
- undefined - 如果变量是 Undefined 类型的
- boolean - 如果变量是 Boolean 类型的
- number - 如果变量是 Number 类型的
- string - 如果变量是 String 类型的
- object - 如果变量是一个对象或 Null或者数组
- function -如果变量是个函数名
- symbol -es6引入的数据类型
注意不要和JavaScript基本数据类型搞混,
基本数据类型有7个:undefined、null、Boolean、String、Number、Object、Symbol (根据阮一峰老师的教程,基本数据类型就这7种,不包括Array)
- 每次创建Symbol,它的值都不一样
- Symbol里面可以传入一个参数,用于描述你创建的Symbol,传入参数对他的值没有影响
- 应用:在不同的块中,临时重写变量
- Symbol 值不能与其他类型的值进行运算,会报错。
- Symbol 值作为对象属性名时,不能用点运算符
new做了什么
- 无论什么时候,只要创建一个新函数,就会根据一组特定的规则为该函数创建一个
prototype属性,这个属性指向函数的原型对象。 - 在默认情况下,所有原型对象都会自动获得一个
constructor(构造函数)属性,这个属性包含一个指向prototype属性所在函数的指针(就是指向新创建的函数)。 - 通过这个构造函数(原型对象的构造函数),可以继续为原型对象添加其他属性和方法。
- 当调用构造函数创建一个新实例后,该实例的内部将包含一个指针(内部属性),指向构造函数的原型对象。
ECMA-262第5版管这个指针叫[[Prototype]]。脚本中没有标准的方式访问[[Prototype]],但Firefox、Safari和Chrome在每个对象上都支持一个属性__proto__;而在其他实现中,这个属性对脚本是完全不可见的。不过,要明确的真正重要的一点就是,这个连接存在于实例和构造函数的原型对象之间,而不是存在于实例和构造函数之间