无题. 相见时难别亦难
相见时难别亦难, 东风无力百花残
春蚕到死丝方尽, 蜡炬成灰泪始干
晓镜但愁云鬓改, 夜吟应觉月光寒
蓬山此去无多路, 青鸟殷勤为探看
唐, 李商隐
JavaScript 基本语法及概念
JavaScript 是一种脚本语言, ECMA(European Computer Manufacturers Association)组织定制了 JavaScript 语言的标准, 被称为 ECMAScript 标准最新版 ECMAScript 7 标准 (简称 ES7) 已经在 2016 年 6 月正式发布了, 所以, 讲到 JavaScript 的版本, 实际上就是说它实现了 ECMAScript 标准的哪个版本
由于 JavaScript 的语法和 Java 语言类似, 这里我们只介绍有区别或需要了解的语法及概念
变量
声明一个变量用 var 语句, 比如:
- var a; // 声明了变量 a, 此时 a 的值为 undefined
- var $b = 1; // 声明了变量 $b, 同时给 $b 赋值, 此时 $b 的值为 1
- var s_007 = '007'; // s_007 是一个字符串
- var Answer = true; // Answer 是一个布尔值 true
- var t = null; // t 的值是 null
常量
ES6 标准引入了新的关键字 const 来定义常量, const 与 let 都具有块级作用域:
const PI = 3.14;
对象
JavaScript 的对象是一种无序的集合数据类型, 它由若干键值对组成 JavaScript 的对象用于描述现实世界中的某个对象例如, 为了描述小明这个淘气的小朋友, 我们可以用若干键值对来描述他:
- var xiaoming = {
- name: '小明',
- birth: 1990,
- school: 'No.1 Middle School',
- height: 1.70,
- weight: 65,
- score: null
- }
JavaScript 用一个 {...} 表示一个对象, 键值对以 xxx: xxx 形式声明, 用, 隔开获取属性值:
- xiaoming.name; // '小明'
- xiaoming.birth; // 1990
函数
在 JavaScript 中, 定义函数的方式如下:
- function abs(x) {
- if (x >= 0) {
- return x;
- } else {
- return - x;
- }
- }
如果没有 return 语句, 函数执行完毕后也会返回结果, 只是结果为 undefined 由于 JavaScript 的函数也是一个对象, 上述定义的 abs() 函数实际上是一个函数对象, 而函数名 abs 可以视为指向该函数的变量
因此, 第二种定义函数的方式如下:
- var abs = function(x) {
- if (x >= 0) {
- return x;
- } else {
- return - x;
- }
- };
在这种方式下, function (x) { ... } 是一个匿名函数, 它没有函数名但是, 这个匿名函数赋值给了变量 abs , 所以通过变量 abs 就可以调用该函数
上述两种定义完全等价, 注意第二种方式按照完整语法需要在函数体末尾加一个;, 表示赋值语句结束
调用定义的函数:
- abs(10); // 返回 10
- abs(-9); // 返回 9
箭头函数
ES6 标准新增了一种新的函数: Arraw Function(箭头函数)为什么叫 Arrow Function? 因为它的定义用的就是一个箭头:
x => x * x
上面的箭头函数相当于:
- function(x) {
- return x * x;
- }
箭头函数相当于匿名函数, 并且简化了函数定义箭头函数有两种格式, 一种像上面的, 只包含一个表达式, 连 { ... } 和 return 都省略掉了还有一种可以包含多条语句, 这时候就不能省略 { ... } 和 return :
- x = >{
- if (x > 0) {
- return x * x;
- } else {
- return - x * x;
- }
- }
上面的例子是只有一个参数的箭头函数, 无参的箭头函数或多个参数的箭头函数需要使用圆括号:
- var a = () = >4 * 4;
- var xy = (x, y) = >x * y;
strict 模式
strict 模式是用于避免由于 JavaScript 设计缺陷而导致潜在的严重的 bug, 启用 strict 模式的方法是在 JavaScript 代码的第一行写上:
'use strict';
这是一个字符串, 不支持 strict 模式的浏览器会把它当做一个字符串语句执行, 支持 strict 模式的浏览器将开启 strict 模式运行 JavaScript
变量作用域
在 JavaScript 中, 用 var 声明的变量实际上是有作用域的如果一个变量在函数体内部声明, 则该变量的作用域为整个函数体, 在函数体外不可引用该变量:
- 'use strict';
- function foo() {
- var x = 1;
- x = x + 1;
- }
- x = x + 2; // ReferenceError! 无法在函数体外引用变量 x
块级作用域 let
由于 JavaScript 的变量作用域实际上是函数内部, 我们在 for 循环等语句块中是无法定义具有局部作用域的变量的:
- 'use strict';
- function foo() {
- for (var i = 0; i < 100; i++) {
- //
- }
- i += 100; // 仍然可以引用变量 i
- }
为了解决块级作用域, ES6 引入了新的关键字 let , 用 let 替代 var 可以声明一个块级作用域的变量:
- 'use strict';
- function foo() {
- var sum = 0;
- for (let i = 0; i < 100; i++) {
- sum += i;
- }
- i += 1; // SyntaxError
- }
比较运算符
JavaScript 在设计时, 有两种比较运算符:
第一种是 == 比较, 它会自动转换数据类型再比较, 很多时候, 会得到非常诡异的结果;
第二种是 === 比较, 它不会自动转换数据类型, 如果数据类型不一致, 返回 false , 如果一致, 再比较
由于 JavaScript 这个设计缺陷, 不要使用 == 进行比较, 始终坚持使用 === 进行比较
模块
ES6 引入了模块的概念, 一个模块就是一个独立的 js 文件 ES6 模块的设计思想是尽量的静态化, 使得编译时就能确定模块的依赖关系, 以及输入和输出的变量模块功能主要由两个命令构成: export 和 importexport 命令用于规定模块的对外接口, import 命令用于输入其他模块提供的功能
- profile.js
- export var firstName = 'Michael';
- export var lastName = 'Jackson';
- export var year = 1958;
- // or
- var firstName = 'Michael';
- var lastName = 'Jackson';
- var year = 1958;
- export {firstName, lastName, year};
下面的 import 命令, 用于加载 profile.js 文件, 并从中输入变量大括号里面的变量名, 必须与被导入模块 ( profile.js ) 对外接口的名称相同 import 后面的 from 指定模块文件的位置, 可以是相对路径, 也可以是绝对路径,.js 后缀可以省略如果 import 指定的是文件夹的路径, 默认会去找指定目录下的 index.js 文件如果只是模块名, 不带有路径, 那么必须有配置文件, 告诉 JavaScript 引擎该模块的位置
- main.js
- // main.js
- import {firstName, lastName, year} from './profile.js';
- function setName(element) {
- element.textContent = firstName + ' ' + lastName;
- }
除此之外, 我们还可以使用 ** export default ** 命令为模块指定默认输出:
- export-default.js
- export default function () {
- console.log('foo');
- }
其他模块加载该模块时, import 命令可以为该匿名函数指定任意名字:
- import customName from './export-default';
- customName(); // 'foo'
上面代码的 import 命令, 可以用任意名称指向 export-default.js 输出的方法, 这时就不需要知道原模块输出的函数名需要注意的是, 这时 import 命令后面不使用大括号 export default 命令用于指定模块的默认输出显然, 一个模块只能有一个默认输出, 因此 export deault 命令只能使用一次所以, import 命令后面才不用加大括号, 因为只可能对应一个方法
如果想在一条 import 语句中, 同时输入默认方法和其他变量, 可以写成下面这样:
- import customName, { otherMethod } from './export-default';
- class
ES6 引入了 Class(类)这个概念, 通过使用 class 关键字, 可以定义一个类:
- class Point {
- constructor(x, y) {
- this.x = x;
- this.y = y;
- }
- toString() {
- return '(' + this.x + ',' + this.y + ')';
- }
- }
上面代码定义了一个类, 可以看到里面有一个 constructor 方法, 这就是构造方法, 而 this 关键字则代表实例对象 Point 类除了构造方法, 还定义了一个 toString 方法
注意, 定义类的方法的时候, 前面不需要加上 function 这个关键字, 直接把函数定义放进去了就可以了
使用 new 关键字创建一个类的实例
- var point = new Point(2, 3);
- point.toString();
创建匿名类:
- let person = new class {
- constructor(name) {
- this.name = name;
- }
- sayName() {
- console.log(this.name);
- }
- }('张三');
- person.sayName(); // "张三"
使用 extends 关键字继承一个类:
- class ColorPoint extends Point {
- constructor(x, y, color) {
- super(x, y); // 调用父类的 constructor(x, y)
- this.color = color;
- }
- toString() {
- return this.color + ' ' + super.toString(); // 调用父类的 toString()
- }
- }
在 Class 内部可以使用 get 和 set 关键字自定义属性的 getter 和 setter 方法:
- class MyClass {
- constructor() {
- // ...
- }
- get prop() {
- return 'getter';
- }
- set prop(value) {
- console.log('setter:' + value);
- }
- }
- let inst = new MyClass();
- inst.prop = 123; // setter: 123
- console.log(inst.prop); // 'getter'
使用 static 关键字定义静态方法, 静态方法可以直接使用类名调用:
- class Foo {
- static classMethod() {
- return 'hello';
- }
- }
- Foo.classMethod() // 'hello'
参考
- https://www.liaoxuefeng.com/
- http://es6.ruanyifeng.com/
来源: http://www.jianshu.com/p/53048f34eec5