1. 变量
var 关键字
使用var操作符定义的变量会成为包含它的函数的局部变量。使用var关键字声明的变量会自动提升到函数作用域顶部,此外可以反复多次使用var声明同一个变量
let声明
let 和var声明作用差不多,但是有着非常重要的区别。最明显的区别就是,let声明的范围是块作用域,而var声明的范围是函数作用域。同时let函数在同一个作用域中不允许重复定义相同名称的变量
暂时性死区
在解析代码的时候,javascript 引擎会注意出现在块后面的let声明,只不过在此之前不能以任何的方式来引用未声明的变量,在let声明之前的执行瞬间成为暂时性死区
全局声明
与var关键字不同,使用let在全局作用域声明的变量不能成为window对象的属性
for循环的let声明
在let声明出现之前,for循环定义的迭代变量会渗透到循环外部,改用let声明之后,迭代变量不会渗透到外部,这是因为let的块作用域。使用var循环最常见的问题是,循环退出的时候,输出的始终是最后的结果,这是因为var声明的迭代变量的左右域声明是函数,也就是说,迭代变量声明在for循环之外的。迭代变量保存的值是循环推出的额值,而使用let声明的迭代变量,JavaScript引擎在后台会为每个迭代循环声明一个新的迭代变量,每次settimeout引用的都是不同的迭代变量
const声明
const的行为和let基本相同,唯一一点重要的区别是const声明变量的时候一定要初始化变量,且尝试修改const声明的变量会导致报错。const声明的限制只适用于它指向的变量引用,换句话说,如果const声明的变量是一个引用对象,那么修改这个对象内部的属性并不违反const限制
声明风格以及最佳实践
ES6添加let和const声明从客观上来说是为这门语言更加精确的声明作用域和语法提供了更好的支持。在项目中不推荐使用var声明变量,const优先使用,let次之。使用const声明可以让浏览器运行时保持变量不变,也可以让静态的代码分析工具提前发现不合法的赋值操作,因此推荐使用const来声明变量,只有提前知道未来会有修改时,在使用let。这样可以让开发者更加有信心推断某些变量永远不会变化
2.0 数据类型
ES的数据类型时松散的,所有需要一定的手段来确定任何变量的数据类型。typeof操作符号就是为了检测数据的类型。对一个值使用typeof操作符会返回下列字符串
- undefined:表示未定义
- boolean:表示布尔值
- string: 表示字符串
- number:表示数值
- object 表示为对象或者null
- function 表示函数
- symbol:表示符号
undefined
undefined表示未定义,未声明的变量和初始化未定义的变量使用typeof操作符,得到的结果都是undefined
Null
Null类型就是一个值,即特殊的null,从逻辑上讲null是一个空对象指针,这也是null对象使用typeof的时候返回object的原因
Boolean
Boolean类型有两个数值true/false。其他类型可以使用Boolean()装箱函数转换成布尔类型。转换规则如下
数据类型 | 抓换成true的值 | 转换成false的值 |
---|---|---|
Boolean | true | false |
String | 非空字符串 | '' |
Number | 非零数值(包括无穷大) | 0 Nan |
object | 任意对象 | null |
undefined | N/A | undefine |
Number类型
Number类型格式表示整数和浮点数。浮点数的精度是17位。有3个函数可以将非数值转换成数值:Number() ,parseInt(),parseFloat().Number()是转换函数,可以用于任何数据类型。parseInt()和parseFloat()这两个函数主要是讲字符串转换成数值。
- parseInt()函数专注于把字符串转换成数值,parseInt函数的第二个参数表示字符串的进制
let number = parseInt('0xAF',16) // 175 - toString()函数可以把数值转换成字符串,同时第一个参数也表示禁止
let string = '15'.toString(16) //F
String类型
字符串可以使用单引号(''),双引号("")或者反引号(``)表示。ES6中添加字符串插值。字面量的插值,其实是调用的toString()进行强制转换
Symbol类型
Symbol是ES6中新增的数据类型。符号是原始值,符号实例时唯一,不可变的。符号的用途时确保对象属性唯一标识符。不会发生属性冲突
Symbol.for()
如果运行时的不同部分需要共享和重用符号实例,那么可以用一个字符串作为键,在全局符号注册中中创建并重用符号。为此需要使用Symbol.for()函数。但是这个函数只能使用字符串。
let foo = Symbol.for('foo')
let foo1 = Symbol.for('foo')
console.log(foo ==== foo1) // true
内置符号
Symbol.asyncInterator
这个符号作为一个属性表示一个方法,该方法返回默认的AsyncInterator.有for-awit-of语句使用。这个符号表示实现异步迭代的函数。
class Emitter {
constructor(max) {
this.max = max;
this.asyncIdx = 0;
}
async *[Symbol.asyncIterator]() {
while (this.asyncIdx < this.max) {
yield new Promise((resolve) => resolve(this.asyncIdx++));
}
}
}
async function asyncCount() {
const emitter = new Emitter(5);
for await (const x of emitter) {
console.log(x);
}
}
asyncCount();
Symbol.hasInterator
该方法决定一个构造器对象是否认可一个对象是它的实例.由 instanceof 操作符可以确定一个对象实例的原型上是否有原型
class Bar {}
class Baz extends Bar {
static [Symbol.hasInstance]() {
return false;
}
}
const r = new Bar();
console.log(r instanceof Bar);
const z = new Baz();
console.log(z instanceof Baz);
function test() {
for (let index = 0; index < 10; index++) {
console.log("index")
break;
}
}
test();
其他一些 Symbol 属性
Symbol还有很多属性对应相应的方法
属性 | 方法 | 含义 |
---|---|---|
Symbol.isConcatSpreadable | Array.prototype | 数组打平 |
Symbol.iterator | for-of | for-of 循环 |
Symbol.math | String.prototype.match | 字符串匹配 |
Symbol.replace | String.prototype.replace | 字符串替换 |
Symbol.search | String.prototype.search | 字符串搜索 |
Symbol.split | String.prototype.split | 字符串裁剪 |
Symbol.toPrimitive | 对象的默认行为 |
class Bar {
constructor() {
this[Symbol.toPrimitive] = function (hint) {
console.log("hint:", hint);
switch (hint) {
case "number":
return 3;
case "string":
return "view";
case "default":
return "ddddd";
}
};
}
}
const bar = new Bar();
// const a = 1 - bar;
// console.log("a:", a);
const string = String(bar);
console.log("s:", string);
网友评论