ES6 和 JavaScript 的关系
- ES6 全称ECMAScript 6.0, ECMA 是一个标准化组织,1996 年 11 月,JavaScript 的创造者 Netscape 公司,将 JavaScript 提交给标准化组织 ECMA,次年,ECMA 发布 262 号标准文件(ECMA-262)的第一版,规定了浏览器脚本语言的标准,并将这种语言称为 ECMAScript,这个版本就是 1.0 版。
该标准从一开始就是针对 JavaScript 语言制定的,但是之所以不叫 JavaScript,有两个原因。一是商标,Java 是 Sun 公司的商标,根据授权协议,只有 Netscape 公司可以合法地使用 JavaScript 这个名字,且 JavaScript 本身也已经被 Netscape 公司注册为商标。二是想体现这门语言的制定者是 ECMA,不是 Netscape,这样有利于保证这门语言的开放性和中立性。
因此,ECMAScript 和 JavaScript 的关系是,前者是后者的规格,后者是前者的一种实现(另外的 ECMAScript 方言还有 JScript 和 ActionScript)。日常场合,这两个词是可以互换的。
ES6 在 2015 年 6 月发布,以后每年 6 月分发布一个小的版本 - json 全称:JavaScript Object Notation
- 万维网: World Wide Web
- JavaScript 是一种动态类型语言,也就是说,变量的类型没有限制,变量可以随时更改类型。
var a = 1;
a = 'hello';
- 如果使用var重新声明一个已经存在的变量,是无效的。
var x = 1;
var x; // 这次是无效的
x // 1
但是,如果第二次声明的时候还进行了赋值,则会覆盖掉前面的值。
var x = 1;
var x = 2; //会覆盖前面的值 等同于 var x; x = 2;
- JavaScript 引擎的工作方式是,先解析代码,获取所有被声明的变量,然后再一行一行地运行。这造成的结果,就是所有的变量的声明语句,都会被提升到代码的头部,这就叫做变量提升(hoisting)。
console.log(a);
var a = 1;
最后的结果是显示undefined,表示变量a已声明,但还未赋值。
- 标识符:
第一个字符,可以是任意 Unicode 字母(包括英文字母和其他语言的字母),以及美元符号($)和下划线(_)。
第二个字符及后面的字符,除了 Unicode 字母、美元符号和下划线,还可以用数字0-9。 - 注释:
// 单行注释
/* 块注释 */
由于历史上 JavaScript 可以兼容 HTML 代码的注释,所以也被视为合法的单行注释。
x = 1; <!-- x = 2;
--> x = 3;
上面代码中,只有x = 1会执行,其他的部分都被注释掉了。需要注意的是,-->只有在行首,才会被当成单行注释,否则会当作正常的运算。
- switch
switch语句后面的表达式,与case语句后面的表示式比较运行结果时,采用的是严格相等运算符(===),而不是相等运算符(==),这意味着比较时不会发生类型转换。
var x = 1;
switch (x) {
case true:
console.log('x 发生类型转换');
break;
default:
console.log('x 没有发生类型转换');
}
上面代码中,由于变量x没有发生类型转换,所以不会执行case true的情况。这表明,switch语句内部采用的是“严格相等运算符”
- 标签:
JavaScript 语言允许,语句的前面有标签(label),相当于定位符,用于跳转到程序的任意位置,标签的格式如下。
top:
for (var i = 0; i < 3; i++){
for (var j = 0; j < 3; j++){
if (i === 1 && j === 1) break top;
console.log('i=' + i + ', j=' + j);
}
}
上面代码为一个双重循环区块,break命令后面加上了top标签(注意,top不用加引号),满足条件时,直接跳出双层循环。如果break语句后面不使用标签,则只能跳出内层循环,进入下一次的外层循环。
top:
for (var i = 0; i < 3; i++){
for (var j = 0; j < 3; j++){
if (i === 1 && j === 1) continue top;
console.log('i=' + i + ', j=' + j);
}
}
上面代码中,continue命令后面有一个标签名,满足条件时,会跳过当前循环,直接进入下一轮外层循环。如果continue语句后面不使用标签,则只能进入下一轮的内层循环。
数据类型
- JavaScript 的数据类型,共有六种:
- 数值(number):整数和小数(比如1和3.14)。
- 字符串(string):文本(比如Hello World)。
- 布尔值(boolean):表示真伪的两个特殊值,即true(真)和false(假)。
- undefined:表示“未定义”或不存在,即由于目前没有定义,所以此处暂时没有任何值。
- null:表示空值,即此处的值为空。
对象(object):各种值组成的集合。 - ES6 又新增了第七种 Symbol 类型的值
获取变量类型
- instanceof
- Object.prototype.toString
- typeof
if (typeof v === "number") {
}
-
null与undefined都可以表示“没有”,含义非常相似。将一个变量赋值为undefined或null,老实说,语法效果几乎没区别。相等运算符(==)甚至直接报告两者相等。在if语句中,它们都会被自动转为false。null 转化成数字时,自动变成 0,undefined 是一个表示此处无定义的原始值,转为数值时是 NaN。null表示空值,即该处的值现在为空。调用函数时,某个参数未设置任何值,这时就可以传入null,表示该参数为空。对象属性没有赋值为 undefined, 函数没有返回值默认返回 undefined
-
布尔值:
如果 JavaScript 预期某个位置应该是布尔值,会将该位置上现有的值自动转为布尔值。转换规则是除了下面六个值被转为false,其他值都视为true。 -
undefined
-
null
-
false
-
0
-
NaN
-
""或''(空字符串)
数值
- JavaScript 内部,所有数字都是以64位浮点数形式储存,即使整数也是如此。所以,1与1.0是相同的,是同一个数。
- 由于浮点数不是精确的值,所以涉及小数的比较和运算要特别小心。
0.1 + 0.2 === 0.3 // false
0.3 / 0.1 // 2.9999999999999996
(0.3 - 0.2) === (0.2 - 0.1) // false
-
根据国际标准 IEEE 754,JavaScript 浮点数的64个二进制位,从最左边开始,是这样组成的。
-
第1位:符号位,0表示正数,1表示负数
-
第2位到第12位(共11位):指数部分
-
第13位到第64位(共52位):小数部分(即有效数字)
-
js 中有正零和负零, 两者是等价的只有在做分母时返回的值不相等
-0 === +0 // true
(-0).toString() // '0'
(+0).toString() // '0'
(1 / +0) === (1 / -0) // false ,这是因为除以正零得到+Infinity,除以负零得到-Infinity,这两者是不相等的
NaN
- NaN是 JavaScript 的特殊值,表示“非数字”(Not a Number),主要出现在将字符串解析成数字出错的场合。
Math.acos(2) // NaN
Math.log(-1) // NaN
Math.sqrt(-1) // NaN
- 要注意的是,NaN不是独立的数据类型,而是一个特殊数值,它的数据类型依然属于Number,使用typeof运算符可以看得很清楚。
typeof NaN // 'number'
- NaN不等于任何值,包括它本身。
NaN === NaN // false
- NaN在布尔运算时被当作false
Boolean(NaN) // false
- NaN与任何数(包括它自己)的运算,得到的都是NaN。
NaN + 32 // NaN
Infinity
- Infinity表示“无穷”,用来表示两种场景。一种是一个正的数值太大,或一个负的数值太小,无法表示;另一种是非0数值除以0,得到Infinity
- Infinity大于一切数值(除了NaN),-Infinity小于一切数值(除了NaN)
Infinity > 1000 // true
- Infinity与NaN比较,总是返回false。
Infinity > NaN
- Infinity的四则运算,符合无穷的数学计算规则。
5 * Infinity // Infinity
与数值相关的全局方法
- parseInt方法用于将字符串转为整数。
parseInt('123') // 123
- 如果parseInt的参数不是字符串,则会先转为字符串再转换。
parseInt(1.23) // 1
- 字符串转为整数的时候,是一个个字符依次转换,如果遇到不能转为数字的字符,就不再进行下去,返回已经转好的部分。
parseInt('8a') // 8
parseInt('12**') // 12
parseInt('12.34') // 12
parseInt('15e2') // 15
parseInt('15px') // 15
-
如果字符串的第一个字符不能转化为数字(后面跟着数字的正负号除外),返回NaN。
parseInt('abc') // NaN
-
如果字符串以0x或0X开头,parseInt会将其按照十六进制数解析。
parseInt('0x10') // 16
-
parseFloat方法用于将一个字符串转为浮点数。
字符串
- 如果要在单引号字符串的内部,使用单引号,就必须在内部的单引号前面加上反斜杠,用来转义。双引号字符串内部使用双引号,也是如此。
'Did she say \'Hello\'?'
// "Did she say 'Hello'?"
"Did she say \"Hello\"?"
// "Did she say "Hello"?"
- 如果长字符串必须分成多行,可以在每一行的尾部使用反斜杠,这样输出的时候还是一行。注意,反斜杠的后面必须是换行符,而不能有其他字符(比如空格),否则会报错。
var longString = 'Long \
long \
long \
string';
- js 不支持多行字符串,如果需要可以自己想办法解决
- 字符串可以被视为字符数组,因此可以使用数组的方括号运算符,用来返回某个位置的字符(位置编号从0开始)。但是,字符串与数组的相似性仅此而已。实际上,无法改变字符串之中的单个字符。
var s = 'hello';
s[0] // "h"
s[1] // "e"
s[4] // "o"
s[1] = 'a'; // 尝试修改索引值为 1 的字符
s // "hello"
- JavaScript 使用 Unicode 字符集,JavaScript 不仅以 Unicode 储存字符,还允许直接在程序中使用 Unicode 码点表示字符,即将字符写成\uxxxx的形式,
var f\u006F\u006F = 'abc';
foo // "abc"
对象
- JS 的对象是一种无序的复合数据集合。
// key 加不加引号都可以
var obj = {
foo: 'Hello',
bar: 'World'
};
// 或
var obj = {
'foo': 'Hello',
'bar': 'World'
};
// 如果 key 是数值,会被自动转换为字符串
var obj = {
1: 'a',
3.2: 'b',
1e2: true,
1e-2: true,
.234: true,
0xFF: true
};
- 值可以是任何数据类型,包括函数
- 读/写属性的两种方式
var obj = {
p: 'Hello World'
};
obj.p // "Hello World"
obj['p'] // "Hello World"
var obj = {};
obj.foo = 'Hello';
obj['bar'] = 'World';
- 查看一个对象本身的所有属性,可以使用Object.keys方法
Object.keys(obj);
- delete命令用于删除对象的属性,删除成功后返回true。
delete obj.p // true
- 属性是否存在:in 运算符
in运算符用于检查对象是否包含某个属性(注意,检查的是键名,不是键值),如果包含就返回true,否则返回false。in运算符的一个问题是,它不能识别哪些属性是对象自身的,哪些属性是继承的。
var obj = { p: 1 };
'p' in obj // true
'toString' in obj /
- 属性的遍历:for...in 循环
需要注意两点: - 它遍历的是对象所有可遍历(enumerable)的属性,会跳过不可遍历的属性。
- 它不仅遍历对象自身的属性,还遍历继承的属性。除非继承的属性被设置为不可遍历属性
一般情况下,都是只想遍历对象自身的属性,所以使用for...in的时候,应该结合使用hasOwnProperty方法,在循环内部判断一下,某个属性是否为对象自身的属性。
var person = { name: '老张' };
for (var key in person) {
if (person.hasOwnProperty(key)) {
console.log(key);
}
}
// name
- with 语句:
它的作用是操作同一个对象的多个属性时,提供一些书写的方便。
var obj = {
p1: 1,
p2: 2,
};
with (obj) {
p1 = 4;
p2 = 5;
}
// 等同于
obj.p1 = 4;
obj.p2 = 5;
函数
- JavaScript 允许省略参数。
function f(a, b) {
return a;
}
f(1, 2, 3) // 1
f(1) // 1
f()
f.length // 2 , 函数的length属性与实际传入的参数个数无关,只反映函数预期传入的参数个数。
- 没有办法只省略靠前的参数,而保留靠后的参数。如果一定要省略靠前的参数,只有显式传入undefined。
function f(a, b) {
return a;
}
f( , 1) // SyntaxError: Unexpected token ,(…)
f(undefined, 1) // undefined
- JavaScript 允许函数有不定数目的参数,
var f = function (one) {
console.log(arguments[0]);
console.log(arguments[1]);
console.log(arguments[2]);
}
f(1, 2, 3)
// 1
// 2
// 3
数组
- 任何类型的数据,都可以放入数组,数组内的元素不必是统一类型的
- 本质上,数组属于一种特殊的对象
typeof [1, 2, 3] // "object"
,数组的特殊性体现在,它的键名是按次序排列的一组整数(0,1,2...)。
var arr = ['a', 'b', 'c'];
Object.keys(arr)
// ["0", "1", "2"] ,可以看到 arr 的健名是 0、1、2
- 当数组的某个位置是空元素,即两个逗号之间没有任何值,我们称该数组存在空位(hole)。
var a = [1, , 1];
a.length // 3
- 使用delete命令删除一个数组成员,会形成空位,并且不会影响length属性。
运算符
- 指数运算符:x ** y
- JavaScript 提供两种相等运算符:==和===。,它们的区别是相等运算符(==)比较两个值是否相等,严格相等运算符(===)比较它们是否为“同一个值”。如果两个值不是同一类型,严格相等运算符(===)直接返回false,而相等运算符(==)会将它们转换成同一个类型,再用严格相等运算符进行比较。
布尔运算符
- 且运算符&&:
如果第一个运算子的布尔值为true,则返回第二个运算子的值(注意是值,不是布尔值);如果第一个运算子的布尔值为false,则直接返回第一个运算子的值,且不再对第二个运算子求值。
't' && '' // ""
't' && 'f' // "f"
't' && (1 + 2) // 3
'' && 'f' // ""
'' && '' // ""
if (i) {
doSomething();
}
// 等价于
i && doSomething();
- 或运算符 ||
它的运算规则是:如果第一个运算子的布尔值为true,则返回第一个运算子的值,且不再对第二个运算子求值;如果第一个运算子的布尔值为false,则返回第二个运算子的值。
't' || '' // "t"
't' || 'f' // "t"
'' || 'f' // "f"
'' || '' // ""
-
全局变量:
JavaScript 最大的语法缺点,可能就是全局变量对于任何一个代码块,都是可读可写。这对代码的模块化和重复使用,非常不利。
因此,建议避免使用全局变量。如果不得不使用,可以考虑用大写字母表示变量名,这样更容易看出这是全局变量,比如UPPER_CASE。 -
变量声明:
JavaScript 会自动将变量声明“提升”(hoist)到代码块(block)的头部。 -
建议不要使用相等运算符(==),只使用严格相等运算符(===)。
-
with可以减少代码的书写,但是会造成混淆。
console
-
占位符:
%s 字符串
%d 整数
%i 整数
%f 浮点数
%o 对象的链接
%c CSS 格式字符串 -
console.warn() warn方法输出信息时,在最前面加一个黄色三角,表示警告;
-
console.error() error方法输出信息时,在最前面加一个红色的叉,表示出错
-
console.table() 方法可以将其转为表格显示
var languages = [
{ name: "JavaScript", fileExtension: ".js" },
{ name: "TypeScript", fileExtension: ".ts" },
{ name: "CoffeeScript", fileExtension: ".coffee" }
];
console.table(languages);
输出为:
(index) name fileExtension
0 "JavaScript" ".js"
1 "TypeScript" ".ts"
2 "CoffeeScript" ".coffee"
- console.count() 方法用于计数,输出它被调用了多少次。
- console.dir() 该方法对于输出 DOM 对象非常有用,因为会显示 DOM 对象的所有属性。
- console.dirxml() 方法主要用于以目录树的形式,显示 DOM 节点。
- console.assert() 方法主要用于程序运行过程中,进行条件判断,如果不满足条件,就显示一个错误,但不会中断程序执行。这样就相当于提示用户,内部状态不正确。它接受两个参数,第一个参数是表达式,第二个参数是字符串。只有当第一个参数为false,才会提示有错误,在控制台输出第二个参数,否则不会有任何结果。
- console.time() 、console.timeEnd() 这两个方法用于计时,可以算出一个操作所花费的准确时间。
Object 对象
- Object 构造函数: 可以接受一个参数,如果该参数是一个对象,则直接返回这个对象;如果是一个原始类型的值,则返回该值对应的包装对象
Object(value)与new Object(value)两者的语义是不同的,Object(value)表示将value转成一个对象,new Object(value)则表示新生成一个对象,它的值是value
-
Object.keys方法的参数是一个对象,返回一个数组。该数组的成员都是该对象自身的(而不是继承的)所有属性名。Object.getOwnPropertyNames方法与Object.keys类似,也是接受一个对象作为参数,返回一个数组,包含了该对象自身的所有属性名。
对于一般的对象来说,Object.keys()和Object.getOwnPropertyNames()返回的结果是一样的。只有涉及不可枚举属性时,才会有不一样的结果。Object.keys方法只返回可枚举的属性,Object.getOwnPropertyNames方法还返回不可枚举的属性名。 -
属性描述对象:JavaScript 提供了一个内部数据结构,用来描述对象的属性,控制它的行为,比如该属性是否可写、可遍历等等。这个内部数据结构称为“属性描述对象”(attributes object)。每个属性都有自己对应的属性描述对象,保存该属性的一些元信息,这些属性称为元属性。
{
value: 123, // 是该属性的属性值,默认为undefined。
writable: false, // 表示属性值(value)是否可改变(即是否可写),默认为true
enumerable: true, // 表示该属性是否可遍历,默认为true。如果设为false,会使得某些操作(比如for...in循环、Object.keys())跳过该属性。
configurable: false, // 表示属性的可配置性,默认为true。如果设为false,将阻止某些操作改写属性描述对象,比如无法删除该属性,也不得改变各种元属性(value属性除外)
get: undefined, // 表示该属性的取值函数(getter),默认为undefined。
set: undefined // 表示该属性的存值函数(setter),默认为undefined。
}
- 创建对象一定要用 new 否则构造函数就会被当成普通函数调用,并不会生成实例对象
ES6
- ES6 中使用关键字 new 创建对象时会默认执行 constructor 构造方法
- constructor 中,子类必须通过 super 来调用父类的构造方法,对父类进行初始化,否则会报错
- ES6 使用 extends 关键字来作为类的继承
ES6 的标签模板字符串
- 标签模板字符串(Tagged Template Literals)。
- 正常情况下,我们都是通过 函数名() 方式来进行调用的,其实函数还有另外一种调用方式:
- 如果我们在调用的时候插入其他的变量:
- 模板字符串被拆分了;
- 第一个元素是数组,是被模块字符串拆分的字符串组合,如果以模块字符串结尾,那么会拆出一个空字符串
- 后面的元素是一个个模块字符串传入的内容;
比如如下我们定义一个接收可变参数的test
函数:
function test(...args) {
console.log(args);
}
通常调用 test 函数时,是通过test("abc","bcd")
调用的;
现在还有另一种调用方式就是通过标签模板字符串的方式,比如:
test`aaa`; // 输出 [["aaa"]]
const name = 'zhang';
const age = 18;
test`my name is ${name},age is ${age}`; // 输出[["my name is ", ",age is ", ""],"zhang",18], 这里以插入的${age}结尾, 所以第一个元素多了一个空字符串
网友评论