JavaScripts

5/11/2019 JavaScripts

# 基本介绍

JavaScript 简称 JS

JavaScript 是一种适用于网页的脚本语言!

JavaScript 被数百万计的网页用来改进设计、验证表单、检测浏览器、创建cookies等更多的应用。

JavaScript 是因特网上最流行的脚本语言。

JavaScript 很容易使用!认识她, 爱上她!

浏览器内置了JavaScript语言的解释器,所以在浏览器上按照 JavaScript 语言的规则编写相应代码,浏览器就可以解释并做出相应的处理.

Windows 下,打开浏览器,按下F12

chrome 浏览器

image.png

IE 浏览器

image.png

# 二、如何在 HTML 中使用 JavaScript 的代码 和 编写 JavaScript 代码

# 1. 引入方式

<!-- 方式一 :从一个文件引入-->
<script src="JS文件的路径.js"></script>

<!-- 方式二: 直接在 HTML 文档中代中写入 JS 代码 -->
<script type="text/javascript">
    var li = "Hello 千锋云计算好程序员"
</script>
1
2
3
4
5
6
7

# 2. 应该在 html 文档的哪个位置引入

由于Html代码是从上到下执行,为了不影响用户的体验效果,应该放在 body 标签的底部;

这样的话,即使由于加载js代码耗时严重,也不会影响用户看到页面效果,只是js实现特效慢而已。

<!DOCTYPE html>  <!--HTML5文档标识-->
<html lang="en">
<head>
</head>
<body>
    <div>
       页面内容
    </div>

</body>
    <!-- 引入的方式一 -->
    <script src="my_javascript.js"></script>

    <!-- 引入的方式二 -->
    <script>
        js 代码
    </script>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 三、开发工具的搭建

# 1. Node.js

# 下载和安装

参考官方网站 (opens new window)

# 测试 Node 环境支持 ES6 的程度

# 在系统的终端中执行 npm 安装一个包
npm install -g es-checker

# 之后在系统的终端中执行如下命令
es-checker
1
2
3
4
5

# 四、语法

# 1. JavaScript 代码的注释和代码风格

// 单行

/* 多
   行 */
// 注意:此注释仅在 script 标签内中或者一个 JS 文件中生效
console.log("每行代码后面加英文的分号");
1
2
3
4
5
6

# 2. 调试工具:终端输出,和浏览器弹窗

把一个对象(变量的值) 输出到终端

console.log("Hello JavaScript")
1

在浏览器中把一个对象(变量的值) 以一个小弹窗的方式显示出来

alert("Hello JavaScript")
1

# 3. 变量

JavaScript中变量的声明是一个非常容易出错的点,局部变量必须一个 var 开头,如果未使用var,则默认表示声明的是全局变量。

# ES5 变量的作用域

  • 全局作用域

  • 函数作用域

# 3.1 全局作用域

一对大括号{}内的代码都称为一个作用域

注意: 全局作用域的 变量 可以被重复声明,并且可以被重新赋值。

全局作用域的变量声明有两种方式

# 3.1.1 没有使用任何关键字声明的变量,都是全局变量
s = '千锋'

{
s = "云计算"
}

// function 关键字,定义一个函数,函数名是 f
function f(){
    s = "好程序员"
}
f() // 执行这个函数,以便声明变量 s
console.log(s)  // 输出: 好程序员
1
2
3
4
5
6
7
8
9
10
11
12
# 3.1.2 不是在函数中使用 var 关键字声明的变量,也是全局变量

注意: 必须不能在函数中使用的才可以是全局变量。就是在函数外面或者在代码块中(大括号中{}),比如 if 代码块中。

var n = 10;
var n = 100;
{
    var n = 10;
};

if (1 ===1){
    var n = '千锋云计算';
}

console.log(n)  // 输出:千锋云计算
1
2
3
4
5
6
7
8
9
10
11

# 3.2 函数作用域(局部变量)和局部作用域(ES6)

# 3.2.1 在函数中以关键字 var 开头声明的变量,并且不是在。
function foo(){
    var age=18;
}
foo()
console.log(age)   // 将会报错
1
2
3
4
5
# 3.2.2 Es6 中的 letconst 声明的变量

let 声明的变量只在它所在的代码块有效,在同一个代码块(作用域)下,不可以重复声明,可以被重新赋值。

const 声明的常量只在它所在的代码块有效,在同一个代码块(作用域)下,不可以重复声明,并且不可以被重新赋值(基本类型的数据)。

下面的示例是在 node 的终端中执行的结果。

# let 示例

此代码是在 node 交互终端中运行的结果。

> { let num = 10;
... num = 100;
... console.log("又得" + num);
... }
又得100
undefined
> num
ReferenceError: num is not defined
1
2
3
4
5
6
7
8

for循环的计数器,就很合适使用let命令。

for (let i = 0; i < 10; i++) {
      console.log(i);
}

console.log("在代码块外面打印的变量 i 将会报错")
console.log(i);
// ReferenceError: i is not defined
1
2
3
4
5
6
7
# const 示例

const 主要用于定义一个作用域中的常量,就是这个变量可以在自己的代码块儿中使用,但其值不能被修改。 这个作用域可以全局作用域,也可以是函数作用以及局部作用域。

//对于基本类型,值不能改变
const s = "千锋云计算";
s = "好程序员";  // TypeError: Assignment(分配) to constant(常量) variable.
1
2
3
//对于引用类型,
const obj = {x: 0};
obj = {y: '123'};  // TypeError: Assignment to constant variable.
obj.x = '123';     //obj存储的是一个地址,地址不能变,但对象本身是可变的
1
2
3
4

# 4. 逻辑运算符和判断

# 4.1 逻辑运算符

  • == 比较值相等 1 == "1" 会返回 true

  • != 不等于

  • === 同时比较值和类型相等 1 === "1" 会返回 false

  • || 或

  • && 且

小示例

1 == 1 && 2 == 2 || 3 == "3"
1

JavaScript中支持两个中条件语句,分别是:if 和 switch

# 4.2 if

// 条件 : (1 === 1 && 2 === 2 || 3 === "3")
if(条件){
        // 条件成立后执行的代码
    }else if(条件){
        // 条件成立后执行的代码
    }else{
        // 以上条件都不成立要执行的代码
    }
1
2
3
4
5
6
7
8

# 4.3 switch

switch(name){                 // name 一个变量
        case '1':             // 若果 name 的值等于 "1" 
            age = 123;        // 执行下面这段代码
            break;
        case '2':             //  若果 name 的值等于 "1"
            age = 456;        //  执行下面这段代码
            break;
        default :             //  上面的值都没有匹配到
            age = 777;        //  则执行这段代码
    }
1
2
3
4
5
6
7
8
9
10

# 4.4 三元运算

//  var n = 判断条件 ? 条件为真时执行的表达式 : 条件为假时执行的表达式
var x = 3
var n = x >= 2 ? 5 + 1 : 10
console.log(n)  // 6
1
2
3
4

# 5. 函数

# 5.1 普通函数

// 普通函数
    function func(arg){
        return true;
    }
1
2
3
4

# 5.2 匿名函数

// 匿名函数  特点: 可以被当做参数传递;常用
function(arg){
    return "tony";
}

// 匿名函数的应用
function func(arg){
    arg()
}
func(function (){
    console.log(123);
})
1
2
3
4
5
6
7
8
9
10
11
12

# 5.3 自执行函数

// 自动执行的函数
(function(arg){
    console.log(arg);
})('123')
1
2
3
4

# 6. 箭头函数(ES6)

# 6.1 标准箭头函数的转换

// 普通函数
function f(arg) {
    return arg
}
// 执行普通函数
var ret = f(555);
console.log(ret)

// 转换为箭头函数
var f1 = (arg)=>{return arg};
// 执行箭头函数
var ret2 = f1('world');
console.log(ret2)
1
2
3
4
5
6
7
8
9
10
11
12
13

# 6.2 当函数的参数只有一个时,()可以省略

// 接上一例子,标准箭头函数
var f1 = (arg)=>{return arg};

// 省略 ()
var f1 = arg=>{return arg};
1
2
3
4
5

# 6.3 当函数体中,只有一条 return 语句时,{} 可以省略

// 接上例,省略 {}
var f1 = arg=>arg;
// 执行箭头函数
var ret2 = f1('world');
console.log(ret2)
1
2
3
4
5

# 6.4 函数的默认参数(ES5)

ES5 不支持

let f = (arg1,arg2)=>arg1 +arg2;
console.log(f(1,2));
// python --> f = lambda arg1, arg2: arg1 + arg2

// 参数的默认值
let f2 = (arg1,arg2=10)=>arg1 +arg2;
console.log(f2(1));
console.log(f2(1,20));
1
2
3
4
5
6
7
8

上面代码中,参数变量x是默认声明的,在函数体中,不能用let或const再次声明,否则会报错。

# 7. 数据类型及其操作

# 7.1 总体预览

JavaScript 中的数据类型分为原始类型和对象类型:

  • 原始类型
    • 数字
    • 字符串
    • 布尔值
  • 对象类型
    • 数组
    • 字典
    • ...

特别的: 数字、布尔值、null、undefined、字符串是不可变的类型。

可以使用 typeof 查看类型

name = "yangge"
age = 18
li = [1,2,3]
dic = {"a": 1, "b": 2}
typeof(li)

typeof name

typeof true

typeof false
1
2
3
4
5
6
7
8
9
10
11

# 7.2 布尔类型(Boolean)

布尔类型仅包含真假,与Python不同的是全部是 小写字母falsetrue

# 7.3 字符串

字符串是由字符组成的数组,但在JavaScript中字符串是不可变的:可以访问字符串任意位置的文本,但是JavaScript 并未提供修改已知字符串内容的方法。

一句话和 pytone 的类似的特性

# 常见功能:

注意: 以下的操作不会改变原来的字符串 由于方法较多,不能一一演示。因为这里面的大部分 方法都和 python 中的类似,是指方法的名字不一样而已,道理都一样。

/*长度,注意这是个属性,不是函数,不要加小括号()*/
obj.length

/*移除两端的空白字符*/
obj.trim()

/*移除左边空白 - 自修*/
obj.trimLeft()

/*移除右边空白 - 自修*/
obj.trimRight)

/*拼接*/
obj.concat(value, ...)

/*全部转换为小写*/
obj.toLowerCase()

/*全部转换为大写*/
obj.toUpperCase()

/*分割,返回的是分割好的列表形式;*/
obj.split(delimiter, limit)
          delimiter /*以此字符为标识进行分割,此字符不会出现在分割后的结果里;*/

          limit     /*从分割后的结果中,取出总共几个元素。*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

ES 6 中字符串的新功能

  • 新方法
// startsWith 判断字符串以什么字符为开始,返回一个布尔值
var str = "http://www.qfedu.com"
if (str.startsWith("http://")){
    console.log("http 地址")
} else if(str.startsWith("git")){
          console.log("git 地址")
};
// endsWith  判断字符串以什么为结尾
if (str.endsWith("com")){
    console.log("国际域名")
}

// includes  判断某些字符串是否存在其内
var s = "hello world ";
console.log(s.includes(' '));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

// indexOf 查找元素的索引号 let s = 'qianfeng' s.indexOf(a) // 2

  • 字符串模板
// ES 5
var name = "shark"
var age  = 18
var tag = "<tr><td>" + name + "</td>" +
               "<td>" + age + "<td></tr>"

1
2
3
4
5
6

// ES 6
var name = "shark"
var age = 18
var tag = `<tr>
<td>${name}</td>
<td>${age}</td>
</tr>`
1
2
3
4
5
6
7
8

# 7.4 数组

JavaScript 中的数组类似于 Python 中的列表 同样这里数组的方法所表示的原理和 python 中列表的方法一样 所以应该很快能够理解,不必都演示

// 创建数组
var li = []
var obj = [1, 2, 3]

// 数组元素的数量
obj.length

// 尾部追加元素,会真实的改变原列表
obj.push('c')

// 会删除掉列表里的最后一个元素,并且将这个元素返回
obj.pop()

// 从头部插入一个元素
obj.unshift("shark")

// 从头部移除一个元素
obj.shift()

// 切片;start 起始索引位置,被包含;end 终止索引位置,不被包含
obj.slice(start,end)

// 反转
obj.reverse()

// 将数组元素连接起来以构建一个字符串;
// sep 是一个任意字符
// 拼接后的结果,每个元素之间会以此字符为连接字符,元素类型没有限制,在Python中元素必须是字符。
obj.join(sep)

// 拼接数组, 原来的数组不变,返回拼接好的新对象。
var new_arr = obj.concat(arr1,arr2,..)

// 查找元素的索引号
obj.indexOf(1)
ß
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# 扩展运算符
  • 扩展运算符(spread)是三个点(...)。将一个数组转为用逗号分隔的参数序列。
console.log(...[1, 2, 3]);
1
  • 可以给函数传参
function f(x, y, z) {
  console.log(x);
  console.log(z);
}
let args = [0, 1, 2];
f(...args);
1
2
3
4
5
6
// ES6 的写法
Math.max(...[14, 3, 77])

// 等同于
Math.max(14, 3, 77);
1
2
3
4
5

Math.max() 是 JS 中的内置函数

  • 合并数组
var arr1 = ['a', 'b'];
var arr2 = ['c'];
var arr3 = ['d', 'e'];

// ES5的合并数组
console.log(arr1.concat(arr2, arr3));
// [ 'a', 'b', 'c', 'd', 'e' ]

// ES6的合并数组
console.log([...arr1, ...arr2, ...arr3])
// [ 'a', 'b', 'c', 'd', 'e' ]
1
2
3
4
5
6
7
8
9
10
11
# 数组遍历(for 循环)
const arr = ['a', 'b'];

//  ES5 中得到 索引号
for (let i in li){
    console.log(i);
}
1
2
3
4
5
6

ES6 还提供三个新的方法——entries()keys()values()——用于遍历数组。它们都返回一个遍历器对象,可以用for...of循环进行遍历,唯一的区别是keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历。

for (let index of arr.keys()) {
  console.log(index);
}
// 0
// 1

for (let elem of arr.values()) {
  console.log(elem);
}
// 或者
for (let i of li){
    console.log(i); 
}
// 'a'
// 'b'

// 同时遍历值和索引号
for (let [index, elem] of arr.entries()) {
  console.log(index, elem);
}

// 或者使用 forEach 需要配合函数
li.forEach(function (value,index) {
    console.log(index,value)
});
// 0 "a"
// 1 "b"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# 7.5 对象

在 javaScript 实际上是没有字典和列表的概念的,它们都称为对象;只是我们把它构造称为列表和字典的形式而已。

1ae7f7ad3b63f2298daf43d7bcdbcb0f.png

# 7.5.1 更新对象

Object.assign方法用于对象的合并

Object.assign方法的第一个参数是目标对象,后面的参数都是源对象。

const target = { 'a': 1 };

const source1 = { 'b': 2 };
const source2 = { 'c': 3 };

Object.assign(target, source1, source2);
console.log(target); // {a:1, b:2, c:3}
1
2
3
4
5
6
7
# 7.5.2 遍历对象
const o = {"a": "1", "b": 2}

for (let k in o){
    console.log(o[k])
}

console.log(Object.keys(o));
console.log(Object.values(o));
console.log(Object.entries(o));

// 变量 key
for (let k of Object.keys(o)){
    console.log(k)
}

// 变量 value
for (let val of Object.values(o)){
    console.log(val)
}

// 变量 key 和 value
for (let [k,v] of Object.entries(o)){
    console.log(k,v)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 8.5.3 Map(出现在 ES6)

注意: Map 更像是 python 中的字典,所以以下可以让学员自己联系。不懂的提出来,再单独讲。因为时间有限,不能都讲,其实这些都在 python 中讲解过原理。

JavaScript的对象(Object),本质上是键值对的集合(Hash 结构),但是传统上只能用字符串当作键。这给它的使用带来了很大的限制。

const data = {};
const element = document.getElementById('myDiv');

data[element] = 'metadata';
data['[object HTMLDivElement]'] // "metadata"
1
2
3
4
5

为了解决这个问题,ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。如果你需要“键值对”的数据结构,Map 比 Object 更合适。

const m = new Map();
m.set("a", 'hello');
console.log(m.get("a"));
console.log(m.get("b", 'any'));  // undefined

const o = {p: 'Hello World'};

m.set(o, 'content')
m.get(o) // "content"

m.has(o) // true
m.delete(o) // true
m.has(o) // false
console.log(m.keys());
console.log(m.values());
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const map = new Map([
  ['name', '张三'],
  ['title', 'Author']
]);

map.size // 2
map.has('name') // true
map.get('name') // "张三"
map.has('title') // true
map.get('title') // "Author"
1
2
3
4
5
6
7
8
9
10

Map 实例的属性和操作方法

(1)size 属性

size属性返回 Map 结构的成员总数。

const map = new Map();
map.set('foo', true);
map.set('bar', false);

map.size // 2
1
2
3
4
5

(2)set(key, value)

set方法设置键名key对应的键值为value,然后返回整个 Map 结构。如果key已经有值,则键值会被更新,否则就新生成该键。

const m = new Map();

m.set('edition', 6)        // 键是字符串
m.set(262, 'standard')     // 键是数值
m.set(undefined, 'nah')    // 键是 undefined
1
2
3
4
5

set方法返回的是当前的Map对象,因此可以采用链式写法。

let map = new Map()
  .set(1, 'a')
  .set(2, 'b')
  .set(3, 'c');
1
2
3
4

(3)get(key)

get方法读取key对应的键值,如果找不到key,返回undefined

const m = new Map();

const hello = function() {console.log('hello');};
m.set(hello, 'Hello ES6!') // 键是函数

m.get(hello)  // Hello ES6!
1
2
3
4
5
6

(4)has(key)

has方法返回一个布尔值,表示某个键是否在当前 Map 对象之中。

const m = new Map();

m.set('edition', 6);
m.set(262, 'standard');
m.set(undefined, 'nah');

m.has('edition')     // true
m.has('years')       // false
m.has(262)           // true
m.has(undefined)     // true
1
2
3
4
5
6
7
8
9
10

(5)delete(key)

delete方法删除某个键,返回true。如果删除失败,返回false

const m = new Map();
m.set(undefined, 'nah');
m.has(undefined)     // true

m.delete(undefined)
m.has(undefined)       // false
1
2
3
4
5
6

(6)clear()

clear方法清除所有成员,没有返回值。

let map = new Map();
map.set('foo', true);
map.set('bar', false);

map.size // 2
map.clear()
map.size // 0
1
2
3
4
5
6
7

遍历方法

Map 结构原生提供三个遍历器生成函数和一个遍历方法。

  • keys():返回键名的遍历器。
  • values():返回键值的遍历器。
  • entries():返回所有成员的遍历器。
  • forEach():遍历 Map 的所有成员。

需要特别注意的是,Map 的遍历顺序就是插入顺序。

const map = new Map([
  ['F', 'no'],
  ['T',  'yes'],
]);

for (let key of map.keys()) {
  console.log(key);
}
// "F"
// "T"

for (let value of map.values()) {
  console.log(value);
}
// "no"
// "yes"

for (let item of map.entries()) {
  console.log(item[0], item[1]);
}
// "F" "no"
// "T" "yes"

// 或者
for (let [key, value] of map.entries()) {
  console.log(key, value);
}
// "F" "no"
// "T" "yes"

// 等同于使用map.entries()
for (let [key, value] of map) {
  console.log(key, value);
}
// "F" "no"
// "T" "yes"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

forEach()

map.forEach(function(value, key) {
  console.log("Key: %s, Value: %s", key, value);
});
1
2
3

# 8. ES6 中变量的解构赋值

# 8.1 数组的解构

ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)

以前

let a = 1;
let b = 2;
let c = 3;
1
2
3

现在

let [a, b, c] = [1, 2, 3];
console.log(a,b,c)

let [foo, [[bar], baz]] = [1, [[2], 3]];
console.log(foo, bar, baz);

let [ , , third] = ["foo", "bar", "baz"];
let [head, ...tail] = [1, 2, 3, 4];
// head -> 1
// tail -> [ 2, 3, 4 ]

// 不完全解构
let [x, y, ...z] = ['a'];
// a undefined []

let [x, y] = [1, 2, 3];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

解构的严格条件是,等号右边的数据必须是可迭代(遍历)的结构

下面的将会报错

let [foo] = 1;
let [foo] = false;
let [foo] = undefined;
let [foo] = null;
let [foo] = {};
1
2
3
4
5

# 8.2 对象的解构

对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。

let { bar, foo } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"

let { baz } = { foo: "aaa", bar: "bbb" };
baz // undefined
1
2
3
4
5
6

如果变量名与属性名不一致,必须写成下面这样。

let { foo: baz } = { foo: "aaa", bar: "bbb" };
baz // "aaa"
foo // error: foo is not defined
1
2
3

注意:

上面代码中,foo是匹配的模式,baz才是变量。真正被赋值的是变量baz,而不是模式foo

也就是说,对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。

嵌套的对象解构(扩展知识)

let obj = {
  p: [
    'Hello',
    { y: 'World' }
  ]
};

let { p: [x, { y }] } = obj;
x // "Hello"
y // "World"
1
2
3
4
5
6
7
8
9
10

注意 p 只是匹配模式,不是变量

指定默认值(自修)

var {x = 3} = {};
x // 3

var {x, y = 5} = {x: 1};
x // 1
y // 5

var {x: y = 3} = {};
y // 3

var {x: y = 3} = {x: 5};
y // 5

var { message: msg = 'Something went wrong' } = {};
msg // "Something went wrong"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

默认值生效的条件是,对象的属性值严格等于undefined

var {x = 3} = {x: undefined};
x // 3

var {x = 3} = {x: null};
x // null
1
2
3
4
5

# 9. 序列化 JSON

  • JSON.stringify(obj) 序列化 将 JS 的数据类型(对象或数组)转化为 JSON 标准数据,在 开发语言中这个数据的类型是字符串。
  • JSON.parse(str) 反序列化 将含有 标准的 JSON 数据转化为 JavaScript 相应的对象
// 序列化,转化为 JSON
var json_arr = [1,'a',2,'b']
var json_str = JSON.stringify(json_arr)

var json_o = {'a': 1}
var json_str = JSON.stringify(json_o)

// 反序列化,转换为 对象
JSON.parse(json_str)
JSON.parse('{"a":1}')
1
2
3
4
5
6
7
8
9
10

注意: 留心 JSON 数据的单、双引号。 JSON 的数据中,字符串表示的,都必须使用双引号,最外层使用单引号。 '{"name": "shark", "age": 18, "other": "30"}'

# JSON 的简写 重要

  1. 当定义的 JSON 对象中的 key 和其对应 value 一样时可以只写一个。
  2. 当定义的 JSON 对象中含有函数时,可以把 冒号和function 省略。
let a = 10
let b = 20

var json = {
    a,    // 相当于'a': a
    b,
    'c': 30,
    show(){
    console.log(this.a)
    }
}

json.show()
1
2
3
4
5
6
7
8
9
10
11
12
13

# 10. 获取时间

//获取当前标准时间对象,就像这个样子:
//   Tue Apr 18 2017 21:35:41 GMT+0800 (中国标准时间)
var da = new Date();

// 获取当前年份: 2018
var year = da.getFullYear();

// 获取当前的月份,注意 JavaScript 的月份是从 0 - 11 的,所以需要加上 1
var month = da.getMonth()  + 1;

// 当前日期 :
 var day = da.getDate();

// 当前小时:
var hours = da.getHours();

// 当前分钟:
var minutes = da.getMinutes();

// 当前秒 :
var seconds = da.getSeconds();

// 把获取到的字符串,按照一定的格式(自定义的)拼接起来
// ES 5
var date_str = "当前时间: " + year + "-" + month + "-" + day + " " + hours+":"+ minutes + ":" + seconds;

// ES 6
var date_fmt = `当前时间: ${year}-${month}-${day}
    ${hours}:${minutes}:${seconds}`;
alert(date_fmt);


//结果应该是像下面的格式一样,但是时间的具体数字肯定不一样
"当前时间: 2018-4-20 19:23:35"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

# 11. 面向对象(扩展知识)

在 JavaScript 中创建一个对象使用 new 这个关键字。

# 11.1 ES5 中实现对象的方式

但是在定义一个类的时候不同的版本是不同的。 ES5 中,定义一个函数,并且这个函数名的首字母大写即可。 首字母大写是规则,不是必须的语法。

ES6 中,可以使用 class 这个关键字了。

this 关键字相当于 python 中的 self, 不同的是在定义一个类方法时 this 关键字不是必须的参数。所以 this 一般总是用在定义变量和使用上变量上。

function Foo(name,age){
    this.Name = name;
    this.Age = age;
}

obj = new Foo('yangge', 18)
obj.Name
1
2
3
4
5
6
7
function Foo(name,age){
    this.Name = name;
    this.Age = age;
    this.show = function(){
        alert(this.Name)
    }
}

obj = new Foo('yangge', 18)
obj.Name
obj.show()

obj2 = new Foo('yangge', 18)
obj2.show()
1
2
3
4
5
6
7
8
9
10
11
12
13
14

原型 prototype

之前的方式会在每次创建实例的时候,函数是属于每个对象的,所以在每次创建新对象的时候,函数都会被创建一次。

利用原型可以实现方法的重用,不论创建多少实例,方法不会每次都被重新创建。

function Foo(name,age){
    this.Name = name;
    this.Age = age;
}

Foo.prototype.show = function(){
    console.log(this.Name);
}
1
2
3
4
5
6
7
8

# 11.2 ES6 中实现对象的方式: class

class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }

    showName() {
        return  this.name;
    }
}

var p1 = new Person("shark",18);
console.log(p1.showName())
1
2
3
4
5
6
7
8
9
10
11
12
13
# constructor 方法

类似 python 中的 __init__

constructor 方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。

一个类必须有 constructor 方法,如果没有显式定义它,一个空的 constructor 方法会被默认添加。

其实和 python 差不多,语言都是相通的。

class Person {
}

// 等同于
class Person {
  constructor(){}
}
1
2
3
4
5
6
7

constructor方法默认返回实例对象(即this

# 11.3 继承(扩展)

Class 可以通过extends关键字实现继承。

class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }

    showName() {
        return  this.name;
    }
}

class TeacherPerson extends Person {
    constructor(name, age, level) {
        super(name, age); // 调用父类的constructor(x, y)
        this.level = level;
    }

    showLevel() {
        return `${this.showName()} - ${this.level}`;
    }

}
var t = new TeacherPerson("shark", 18, 12);
console.log(t);
console.log(t.level);
console.log(t.showLevel());
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

super关键字,它在这里表示父类的构造函数,用来新建父类的this对象。

子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类自己的this对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。如果不调用super方法,子类就得不到this对象。