目录
类C
区分大小写,标识符可以字母、下划线_
、美元符号$
开头
语句以分号;
结尾:虽然不加分号也是被允许的,但会导致性能的降低,也易出现问题
严格模式(strict mode):对一些不规范写法进行处理,对不安全活动将抛出错误。
在脚本开头或函数体开头加上:"use strict";
function do (){
"use strict";
// 函数体
}
var定义的变量会成为包含它的函数的局部变量,函数退出时即被销毁,即声明的范围为函数作用域
var的声明提升(hoist):使用var关键字声明的变量会自动提升到函数作用域的顶部【将所有变量声明拉到函数作用域顶部】
// 以下二者是等价的,均不会报错,输出undefined
function foo() {
console.log(age); // undefined
var age = 20;
}
function foo(){
var age;
console.log(age); // undefined
age = 20;
}
使用var反复多次声明同一个变量是被允许的
function foo(){
var age = 12;
var age = 15;
var age = 18;
var age = 21;
console.log(age); // 21
}
let与var作用类似,不同的是let声明的范围为块作用域
块作用域是函数作用域的子集,因此适用于var的作用域限制同样适用于let
if(true){
var name = "Leo";
console.log(name); // Leo
}
if(true){
let name = "Leo";
console.log(name); // Leo
}
console.log(name); // ReferenceError: name is not defined
在同一个块作用域中,let不允许进行冗余声明是(SyntaxError)
声明冗余报错不会因混用let和var受到影响:这两个关键字声明的不是不同类型的变量,只是指出变量在相关作用域如何存在
var num = 1;
console.log(num); // 1
{
let num = 2;
console.log(num); // 2
}
let num = 1;
console.log(num);
{
var num = 2; // SyntaxError: Identifier 'num' has already been declared
console.log(num);
}
暂时性死区:let声明的变量不会在作用域中被提升(hoist),必须先声明后引用
全局声明:let在全局作用域中声明的变量不会成为window对象的属性,而var声明的变量会
for循环中的let声明:
用var定义迭代变量会渗透到循环体外部,let定义迭代变量的作用域仅局限于for循环块内部
for(var i=0; i<5; i++){
// 循环逻辑
}
console.log(i); // 5
--------------------------
for(let i=0; i<5; i++){
// 循环逻辑
}
console.log(i); // ReferenceError: i is not defined
使用let声明迭代变量,JavaScript引擎在后台为每个迭代循环都声明一个新的迭代变量。
for(var i=0;i<5;i++){
setTimeout(()=>console.log(i),0); // 5 5 5 5 5
}
---------------------------------------
for(let i=0;i<5;i++){
setTimeout(()=>console.log(i),0); // 0 1 2 3 4
}
与let行为基本相同
不允许重复声明,块声明作用域
区别:声明的同时必须初始化,切不可修改const声明的变量的值(TypeError)
使用var或let声明变量但未初始化时,变量会被赋予初始值undefined
具有值undefined的变量与未定义的变量是有区别的
赋值为undefined的变量是存在的,只是值为undefined;未定义的变量不存在,但对其typeof仍会返回undefined。二者是存在根本差别的
let message;
// let age; //确保未被声明过
console.log(message); // undefined
console.log(age); // ReferenceError: age is not defined
console.log(typeof message); // undefined
console.log(typeof age); // undefined
undefined是假值
null表示一个空对象指针,typeof null会返回object
undefined由null派生而来,ECMA-262将他们定义为表面上相等
null是假值
转型函数:Boolean(param);
数据类型
转为true
转为false
Boolean
true
false
String
非空字符串
空字符串
Number
非零数值
0,NaN
Object
任意对象
null
Undefined
\
undefined
八进制字面量:以0o开头,后续数字均为0~7
十六进制字面量:以0x开头,后续数字为0~9和 a~f, 分别代表0~15
浮点值
ECMAScript会想方设法将值转换为整数值:小数点后面没有数字或只有0时,会被转换为整数进行处理
浮点值精度可达17位小数,但算数计算并不精准(IEEE 754数值造成的错误)
console.log( 0.1+0.2 == 0.3 ); // false 0.1+0.2得到结果为0.30000000000000004,出现舍入错误
数值的范围
NaN (Not a Number):表示本来要返回数值的操作失败了
任何涉及NaN的操作均返回NaN,NaN不等于包括NaN在内的任何值
利用 isNaN(param) 函数可以判断一个数是否“不是数值”:此函数会先将不是数值的值尝试转换成数值,任何不能转换为数值的值都会使这个函数返回true
console.log(isNaN(NaN)) // true
console.log(isNaN(10)) // false
console.log(isNaN("10")) // false 可转为数值10
console.log(isNaN("blue")) // true 不可转为数值
console.log(isNaN(true)) // false 可转为数值1
数值转换函数
Number(param):param可为任意数据类型
数据类型
转换规则
Boolean
true转为1,false转为0
Number
直接返回
Null
0
Undefined
NaN
String
只包含数值字符,会被直接转换为数值(包括数字、正负号、小数点)
空字符串会转换为0
包含有效的十六进制格式(0x),会被由十六进制串转换为相对应的十进制数值
Object
调用对象的valueOf( )方法,再按照上述规则转换返回值;若转换结果为NaN,则调用toString( )方法,按照转换字符串的规则转换
parseInt(param1,param2):param1为字符串,param2为进制
直接忽略最前面的空格,从第一个非空格字符串开始转换
第一个非空格字符不是数值字符、正负号,会立即返回NaN(意味着空字符串会返回NaN)
转换直到字符串尾或最后一个非数值字符
console.log(parseInt("1234hello")); // 1234 hello被忽略
console.log(parseInt("12.34")) // 12 .不是有效的整数字符
console.log(parseInt("")); // NaN
console.log(parseInt("0xaf")); // 175 被解释为十六进制
console.log(parseInt("af",16)); // 175 被解释为十六进制
parseFloat(param):与parseInt原理类似
console.log(parseFloat("1234hello")); // 1234 hello被忽略
console.log(parseFloat("12.34.56")); // 12.34
console.log(parseFloat("0123.45")); // 123.45
console.log(parseFloat("3.125e7")); // 31250000
表示零或多个16位Unicode字符序列,通过字符串的length属性可以获取其长度
ECMAScript中的字符串时不可变的,一旦修改某个变量中的字符串值,必须先销毁原字符串再将新的值存入该变量中
向字符串转换
几乎所有值都有方法 toString( ),返回当前值的字符串等价物
Number,Boolean,Object,String均有toString( )方法,null与undefined没有toString( )方法
对Number调用toString( )方法时,可以传一个底数参数,表示以什么底数输出数值的字符串表示
String(param)转型函数
模板字面量:使用反引号,会保留字面量内的换行字符,以跨行定义字符串
字符串插值:模板字面量常用以支持字符串插值,即在一个连续定义中插入一个或多个值
字符串插值通过在 ${...}
中使用一个JavaScript表达式实现,插入的值会使用toString()强制转为字符串
let value = 19;
let str = `<div>
<a href="#">
<span>Leo is ${value} years old</span>
</a>
</div>`;
console.log(str);
标签函数:自定义插值行为,前缀到模板字面量来应用自定义行为
...
将它们收集到一个数组中let value = 19;
let exp = 'second';
function tagFunc(strings, …exp){
console.log(strings);
console.log(exp);
}
tagFunc${value} to the ${exp} power is ${value*value}
;
// [ '', ' to the ', ' power is ', '' ]
// [ 19, 'second', 361 ]
ECMAScript6新增数据类型,确保对象属性使用唯一标识符,不会发生属性冲突的危险
Symbol(string):string为对符号的描述参数,与此符号的定义与标识完全无关
不能与new关键字一起作为构造函数使用,用以避免创建符号包装对象
let sym1 = Symbol('foo');
let sym2 = Symbol('foo');
console.log(sym1 == sym2); // false
全局符号注册表:运行时不同部分需要共享和重用符号实例时,以一个字符串作为键在全局符号注册表创建并重用符号
Symbol.for(string):使用某字符串调用时,检查全局运行时注册表,不存在相应符号则会创建一个新的符号实例,已存在则直接重用
即使采用相同的符号描述,全局注册表中定义的符号与Symbol()定义的符号也不等同
可以用Symbol.keyFor(param)查询全局注册表,param为符号实例,返回对应的描述字符串
let sym1 = Symbol.for('foo'); // 创建一个新的符号实例
let sym2 = Symbol.for('foo'); // 重用已有符号实例
console.log(sym1 === sym2); // true
let sym3 = Symbol('foo');
console.log(sym1 === sym3); // false
console.log(Symbol.keyFor(sym1)); // foo
console.log(Symbol.keyFor(sym3)); // undefined
符号添加为对象属性
let s1 = Symbol('foo'),
s2 = Symbol('bar'),
s3 = Symbol('baz'),
s4 = Symbol('qux');
let obj = { [s1]:'foo val' }; // o[s1] = 'foo val';
Object.defineProperty(obj, s2,{ value: 'bar val', enumerable: true});
Object.defineProperties(obj, {
[s3] : {value:'baz val', enumerable: true},
[s4] : {value:'qux val', enumerable: true},
});
console.log(obj);
//{
// [Symbol(foo)]: 'foo val',
// [Symbol(bar)]: 'bar val',
// [Symbol(baz)]: 'baz val',
// [Symbol(qux)]: 'qux val'
//}
获取对象的符号属性
let s1 = Symbol('foo'),
s2 = Symbol('bar');
let obj = {
[s1]: 'foo val',
[s2]: 'bar val',
baz: 'baz val',
qux: 'qux val'
};
console.log(Object.getOwnPropertySymbols(obj)); // [ Symbol(foo), Symbol(bar) ]
console.log(Object.getOwnPropertyNames(obj)); // [ 'baz', 'qux' ]
console.log(Object.getOwnPropertyDescriptors(obj));
//{
// baz: { value: 'baz val', writable: true, enumerable: true, configurable: true },
// qux: { value: 'qux val', writable: true, enumerable: true, configurable: true },
// [Symbol(foo)]: { value: 'foo val', writable: true, enumerable: true, configurable: true },
// [Symbol(bar)]: { value: 'bar val', writable: true, enumerable: true, configurable: true }
//}
console.log(Reflect.ownKeys(obj)); // [ 'baz', 'qux', Symbol(foo), Symbol(bar) ]
To be continued ……
ECMAScript中的Object是所有对象的基类,任何对象都有这些属性与方法。每个Object实例都有如下属性与方法:
递增/递减:++
/--
前缀时,先改变变量的值再对表达式求值;后缀时,先对表达式求值再改变变量的值
不限于整数,也可作用于以下类型的值
数值类型
规则
String
对有效数值形式则转为数值在改变,变量类型变为Number
对非有效数值形式,变量值变为NaN,变量类型变为Number
Boolean
将false转为0,将true转为1,再进行递增递减操作,变量类型变为Number
float
直接+1或-1(注意:浮点数的加减可能不精确,出现舍入错误)
Object
先调用对象的valueOf()方法,取到的值可操作则直接应用上述规则
如果为NaN,则调用toString()并再次应用其他规则
变量类型从Object变为Number
一元加减:+
/-
&
或|
非~
异或^
<<
:按指定位数将数字的所有位左移(右侧补0,左侧符号位保留)>>
:将所有的32位右移指定位,符号位保留(空位以符号位补充)>>>
:将所有的32位右移指定位,空位以0补充(对于正数无差别,对于负数有很大差异)逻辑非!
:现将操作数统一转为Boolean,再取反
逻辑与&&
:短路操作符,当第一个操作数为false时就不会对第二个操作数求值
可用于任何类型操作数,不一定会返回Boolean值
逻辑或||
:短路操作符,当第一个操作数为true时就不会对第二个操作数求值
可用于任何类型操作数,不一定会返回Boolean值
第一个操作数为Object,则返回第一个操作数;第一个操作数求值为false,则返回第二个操作数
两个操作数均为Object,则返回第一个操作数
两个操作数均为NaN/undefined/null,则返回NaN/undefined/null
可以避免给变量赋值null或undefined
let obj = preferredObj || backupObj;
乘*
除/
取模%
Math.pow(base,power):用于计算base的power次幂
ECMAScript 7新增指数操作符 **
,与Math.pow函数等效
指数操作符同样支持复合赋值操作:**=
console.log(Math.pow(11,2)); // 121
console.log(11**2); // 121
console.log(121**0.5); // 11
加+
:计算数值时,需考虑Infinity,NaN,±0的情况
对两个字符串操作时,将第二个字符串拼到第一个后面;只有一个为字符串时,将另一个转为字符串后再拼在一起
任一操作数为Object时,会调用对象的valueOf()方法,由返回值参与加法运算;没有valueOf则先调用toString,得到的字符串再转为数值参与计算
let obj1 = {
valueOf : function (){
return -1;
},
}, obj2 = {
valueOf : function (){
return "-2";
}
}, obj3 = {
valueOf : function (){
return -2;
}
};
console.log(obj1 + obj2); // -1-2
console.log(obj1 + obj3); // -3
减-
:计算数值时,需考虑Infinity,NaN,±0的情况
包括:>
<
>=
<=
等于==
和不等于!=
:对比较的两操作数先进行强制类型转换,再比较是否相等
全等===
和不全等!==
:比较时不作任何强制类型转换
用于在一条语句中执行多个操作
let num1 = 1, num2 = 2, num3 = 3;
赋值时用逗号操作符分隔值,最终会返回表达式中最后一个值
let num = (5,4,3,2,1,0); // num = 0
用于枚举对象中的非符号键属性
若迭代的变量是null或undefined,则不执行循环体
for (const propName in window){
console.log(propName);
}
用于遍历可迭代对象的元素
会按照可迭代对象的next( )方法产生值的顺序迭代元素
尝试迭代的变量不支持迭代时,语句会抛出错误
let arr = [1,2,3,4];
for (const num of arr){
console.log(num);
}
break语句用于立即退出当前循环,强制执行当前循环后的下一条语句
continue语句也立即退出当前循环,但会再次从循环顶部开始执行
label语句用于给语句加标签,可以通过break和continue语句引用(常用于嵌套循环):强制执行或强制退出标签所在循环
let num = 0;
outermost: for (let i=0; i<10; i++){
for (let j=0; j<10; j++){
if (i===5 && j===5){
break outermost;
}
num ++;
}
}
console.log(num); // 55
-------------------------------------
let num = 0;
outermost: for (let i=0; i<10; i++){
for (let j=0; j<10; j++){
if (i===5 && j===5){
continue outermost;
}
num ++;
}
}
console.log(num); // 95
用于将代码作用域设置为特定的对象,主要用于针对同一对象的反复操作
严格模式下,不允许with语句的使用
let obj = {
value : 114514,
str : 'fuck',
name : 'obj'
};
with (obj) {
console.log(value);
console.log(str);
console.log(name);
}
//114514
//fuck
//obj
在每个case条件分支后,最好都加上break语句,否则代码会在匹配完当前条件后继续匹配下一条件
switch-case语句可以应用所有数据类型,条件的值也可以是变量或表达式
let str = 'hello world';
switch (str) {
case 'hello'+' world':
console.log('Greeting was found!'); //
break;
case 'goodbye':
console.log('Closing was found');
break;
default:
console.log('Unexpected message was found');
}
在比较每个条件分支的值时使用'===',不会强制转换数据类型
手机扫一扫
移动阅读更方便
你可能感兴趣的文章