# Javascript对象

# 函数

# 定义函数

函数可作为封装模块被重复使用,在javascript中定义函数有三种方式:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title></title>
    <script>
        //创建函数方式1:
        var fun1 = new Function("a", "b", "a++;return a+b;");
        console.log(fun1(1, 2));
        //创建函数方式2:
        function fun2(a, b) {
            return a - b;
        }
        console.log(fun2(1, 2))
        //创建函数方式3:
        var fun3 = function (a, b) {
            return a * b;
        }
        console.log(fun3(2, 3));
        console.log(fun3.length);
        //箭头函数(es6语法):
        console.log("箭头函数方式");
        var arr2 = [1, 2, 3, 4, 5];
        arr2.forEach((e) => {
            console.log(e);
        });
    </script>
</head>

<body>
</body>

</html>
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

注意Javascript和类c语言不太一样的地方有:

  1. 方法定义是,形参的类型不用写,返回值类型也不写。
  2. 方法是一个对象,如果定义名称相同的方法,会覆盖。
  3. 在JS中,方法的调用只与方法的名称有关,和参数列表无关。

# 获取调参信息

Javascript获取函数参数,被调用者对象:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title></title>
    <script>
        //获取所有参数
        function add() {
            var sum = 0;
            console.log(arguments.callee);
            for (var i = 0; i < arguments.length; i++) {
                sum += arguments[i];
            }
            return sum;
        }
        console.log(add(1, 2, 3, 4, 5));
    </script>
</head>

<body>
</body>

</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

下列情况会跟我们设想的不一样,javascript中的函数名是对象,常常会变化,如果函数内部依赖于函数名就会出现错误:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title></title>
    <script>
        function fac(num) {
            if (num <= 1) { //0的阶乘也是1
                return 1;
            }
            else {
                return num * fac(num - 1);
            }
        }
        var trueFac = fac;
        fac = function (num) {
            console.log("call fac!");
            return 0;
        };

        console.log(trueFac(10));
    </script>
</head>

<body>
</body>

</html>
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

此时就需要使用callee:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title></title>
    <script>
        function fac(num) {
            if (num <= 1) { //0的阶乘也是1
                return 1;
            }
            else {
                return num*arguments.callee(num-1);
            }
        }
        var trueFac = fac;
        fac = function (num) {
            console.log("call fac!");
            return 0;
        };

        console.log(trueFac(10));
    </script>
</head>

<body>
</body>

</html>
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

此外还可以使用caller来查看函数的调用者:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title></title>
    <script>
        function outer() {
            inner();
        }
        function inner() {
            console.log(inner.caller);
        }
        outer();
    </script>
</head>

<body>
</body>

</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 匿名函数

匿名函数就是没有函数名的函数,它可以:

  1. 赋值到一个变量里,变量相当于函数名。
  2. 利用事件去调用。
  3. 作为对象的方法调用。
  4. 作为其他函数的参数调用。

这里介绍一种好玩的匿名函数,自执行匿名函数,下面是几个常见的:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title></title>
    <script>
        (function () {
            console.log("1");
        })();
        (function (a) {
            console.log(a);
        })("hi");
        (function (a) {
            console.log(a);
            return arguments.callee;
        })("hello")("world");
    </script>
</head>

<body>
</body>

</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

下面是几个不常见的自执行匿名函数:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title></title>
    <script>
        +function () { console.log("1"); }();
        -function () { console.log("2"); }();
        ~function () { console.log("3"); }();
        !function () { console.log("4"); }();
        new function () { console.log("5"); }();
        new function () { console.log("6"); };
        void function () { console.log("7"); }();
        (function () { console.log("8");}());

    </script>
</head>

<body>
</body>

</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# Promise

Promise 是异步编程的一种解决方案:从语法上讲,promise是一个对象,从它可以获取异步操作的消息;从本意上讲,它是承诺,承诺它过一段时间会给你一个结果。promise有三种状态: pending(等待态),fulfiled(成功态),rejected(失败态);状态一旦改变,就不会再变。创造promise实例后,它会立即执行。

它是来解决两个问题的:

  1. 有很多回调函数,前面函数的结果是后面函数的输入。
  2. 异步执行代码,支持多个并发请求。

下面来看示例:

<html>
  <head>
    <title>promise</title>
  </head>
  <body>
    <script>
      function taskA() {
        console.log("Task A");
        // throw new Error("taskA掉坑里了");
      }
      function taskB() {
        console.log("Task B");
        throw new Error("taskB掉坑里了");
      }
      function onRejected(error) {
        console.log("onRejected catch Error: A or B", error);
      }
      function finalTask() {
        console.log("Final Task");
      }

      var promise = Promise.resolve();
      promise
        .then(taskA)                // 和task A/B
        .then(taskB)
        .catch(onRejected)
        .then(finalTask);
     console.log('promise finish');   // promise finish 打印顺序
    </script>
  </body>
</html>
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

# Array

数组是使用单独的变量名来存储一系列值。

# 创建数组

基本有三种方式:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title></title>
    <script>
        var arr1 = new Array(1, 2, 3, 4);
        console.log(arr1)
        var arr2 = new Array(5);
        console.log(arr2)
        var arr3 = ["a", "b", "c", "d"];
        console.log(arr3)
        var arr4 = [1,"a",2,"hello",{name:"xie"}];
        console.log(arr4)
    </script>
</head>

<body>
</body>

</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

注意:

  1. javascript中,数组元素的类型是可变的。
  2. javascript中,数组长度是可变的。

# 常用方法

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title></title>
    <script>
        var arr = [1, "a", 2, "hello", { name: "xie" }];
        console.log(arr.length)
        console.log(arr.join("-"))
        arr.push(456)
        console.log(arr)
        console.log(arr.pop())
        console.log(arr)
    </script>
</head>

<body>
</body>

</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# Map

Map在es6是新引进的,如果是在es5中需要用数组实现:

# ES5

var ZeroRTCMap = function () {
    this._entrys = new Array();
    // 插入
    this.put = function (key, value) {
        if (key == null || key == undefined) {
            return;
        }
        var index = this._getIndex(key);
        if (index == -1) {
            var entry = new Object();
            entry.key = key;
            entry.value = value;
            this._entrys[this._entrys.length] = entry;
        } else {
            this._entrys[index].value = value;
        }
    };
    // 根据key获取value
    this.get = function (key) {
        var index = this._getIndex(key);
        return (index != -1) ? this._entrys[index].value : null;
    };
    // 移除key-value
    this.remove = function (key) {
        var index = this._getIndex(key);
        if (index != -1) {
            this._entrys.splice(index, 1);
        }
    };
    // 清空map
    this.clear = function () {
        this._entrys.length = 0;
    };
    // 判断是否包含key
    this.contains = function (key) {
        var index = this._getIndex(key);
        return (index != -1) ? true : false;
    };
    // map内key-value的数量
    this.size = function () {
        return this._entrys.length;
    };
    // 获取所有的key
    this.getEntrys = function () {
        return this._entrys;
    };
    // 内部函数
    this._getIndex = function (key) {
        if (key == null || key == undefined) {
            return -1;
        }
        var _length = this._entrys.length;
        for (var i = 0; i < _length; i++) {
            var entry = this._entrys[i];
            if (entry == null || entry == undefined) {
                continue;
            }
            if (entry.key === key) {// equal
                return i;
            }
        }
        return -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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

# ES6

参考资料:

使用 Map 对象:

let myMap1 = new Map([
      [1, 'one'],
      [2, 'two'],
      [3, 'three'],
      [1, 'four']
    ])
let myMap = new Map();
let keyObj = {};
let keyFunc = function() {};
let keyString = 'a string';

// 添加键
myMap.set(keyString, "和键'a string'关联的值");
myMap.set(keyObj, "和键keyObj关联的值");
myMap.set(keyFunc, "和键keyFunc关联的值");

myMap.size; // 3

// 读取值
myMap.get(keyString);    // "和键'a string'关联的值"
myMap.get(keyObj);       // "和键keyObj关联的值"
myMap.get(keyFunc);      // "和键keyFunc关联的值"

myMap.get('a string');   // "和键'a string'关联的值"
                         // 因为keyString === 'a string'
myMap.get({});           // undefined, 因为keyObj !== {}
myMap.get(function() {}); // undefined, 因为keyFunc !== function () {}
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

遍历:

let myMap = new Map();
myMap.set(0, "zero");
myMap.set(1, "one");
for (let [key, value] of myMap) {
  console.log(key + " = " + value);
}
// 将会显示两个log。一个是"0 = zero"另一个是"1 = one"

for (let key of myMap.keys()) {
  console.log(key);
}
// 将会显示两个log。 一个是 "0" 另一个是 "1"

for (let value of myMap.values()) {
  console.log(value);
}
// 将会显示两个log。 一个是 "zero" 另一个是 "one"

for (let [key, value] of myMap.entries()) {
  console.log(key + " = " + value);
}

myMap.forEach(function(value, key) {
  console.log(key + " = " + value);
})
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

合并:

let kvArray = [["key1", "value1"], ["key2", "value2"]];

// 使用常规的Map构造函数可以将一个二维键值对数组转换成一个Map对象
let myMap = new Map(kvArray);

myMap.get("key1"); // 返回值为 "value1"

// 使用Array.from函数可以将一个Map对象转换成一个二维键值对数组
console.log(Array.from(myMap)); // 输出和kvArray相同的数组

// 更简洁的方法来做如上同样的事情,使用展开运算符
console.log([...myMap]);

// 或者在键或者值的迭代器上使用Array.from,进而得到只含有键或者值的数组
console.log(Array.from(myMap.keys())); // 输出 ["key1", "key2"]

//复制Map

let original = new Map([
  [1, 'one']
]);

let clone = new Map(original);

console.log(clone.get(1)); // one
console.log(original === clone); //

//Map之间的合并

let first = new Map([
  [1, 'one'],
  [2, 'two'],
  [3, 'three'],
]);

let second = new Map([
  [1, 'uno'],
  [2, 'dos']
]);

// 合并两个Map对象时,如果有重复的键值,则后面的会覆盖前面的。
// 展开运算符本质上是将Map对象转换成数组。
let merged = new Map([...first, ...second]);

console.log(merged.get(1)); // uno
console.log(merged.get(2)); // dos
console.log(merged.get(3)); // three
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
37
38
39
40
41
42
43
44
45
46
47

注意要使用Set方法增加元素,不要直接赋值

let wrongMap = new Map()
wrongMap['bla'] = 'blaa'
wrongMap['bla2'] = 'blaaa2'

console.log(wrongMap)  // Map { bla: 'blaa', bla2: 'blaaa2' }

wrongMap.has('bla')    // false
wrongMap.delete('bla') // false
console.log(wrongMap)  // Map { bla: 'blaa', bla2: 'blaaa2' }


let myMap = new Map()
myMap.set('bla','blaa')
myMap.set('bla2','blaa2')
console.log(myMap)  // Map { 'bla' => 'blaa', 'bla2' => 'blaa2' }

myMap.has('bla')    // true
myMap.delete('bla') // true
console.log(myMap)  // Map { 'bla2' => 'blaa2' }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# Set

Set为集合数据结构,也是es6中加入的。

# 基本使用

let s = new Set([1,2,3])
s.add("school")
console.log(s) // Set(4){1,2,3,"school"}
// 能够通过链式增加,将元素增加到map中
let s = new Set([1,2,3])
s.add("school").add("bus")
console.log(s) // Set(5){1,2,3,"school","bus"}

s.delete(2)
console.log(s) // Set(2){1,3}

s.clear()

s.has(2)

s.size
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# Set遍历

let s = new Set([1,2,3])
s.forEach(item => console.log(item)) // 1 2 3

for(let item of s){
    console.log(item) // 1 2 3
}

for(let item of s.keys()){
    console.log(item) // 1 2 3
}

for(let item of s.values()){
    console.log(item) // 1 2 3
}


// 对于map,key和value是一样的
for(let item of s.entries()){
    console.log(item) // [1,1] [2,2] [3,3]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 去重

//数组去重
let arr = [1,2,3,3,3,2,1]
let s = new Set(arr)
console.log(s) // Set(3){1,2,3}
console.log([...s]) // [1,2,3]
console.log(Array.from(s)) // [1,2,3]

//数组合并后去重
let arr1 = [1,2,3,4]
let arr2 = [2,3,4,5,6]
let s = new Set([...arr1,...arr2])
console.log(s) // Set(6){1,2,3,4,5,6}
console.log([...s]) // [1,2,3,4,5,6]
console.log(Array.from(s)) // [1,2,3,4,5,6]

//两个数组的交加
let arr1 = [1,2,3,4]
let arr2 = [2,3,4,5,6]
let s1 = new Set(arr1)
let s2 = new Set(arr2)
let result = new Set(arr1.filter((item) => s2.has(item)))
console.log(result) // Set(3){2,3,4}

//两个数组差集
let arr1 = [1,2,3,4]
let arr2 = [2,3,4,5,6]
let s1 = new Set(arr1)
let s2 = new Set(arr2)
let s3 = new Set(arr1.filter((item) => !s2.has(item)))
let s4 = new Set(arr2.filter((item) => !s1.has(item)))
console.log(s3) // Map(1){1}
console.log(s4) // Map(1){5,6}
console.log([...s3,...s4]) // [1,5,6]
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

# WeakMap

let ws = new WeakSet()
// ws.add(1) // 报错:因为1不是Object类型,不能增加到WeakMap中。外面只能寄存Object,不能寄存其余数据类型
ws.add({
    name:"lilei"
})
ws.add({
    age:12
})
console.log(ws) // WeakSet{{...},{...}}

//删除对象
let ws = new WeakSet()
// ws.add(1) // 报错:Invalid value used in weak set
ws.add({
    name:"lilei"
})
ws.add({
    age:12
})
ws.delete({
    name:"lilei"
})
console.log(ws) // WeakSet{{...},{...}} 删除之后没有失效,因为对象是援用数据类型,增加对象的地址和删除元素的地址不统一,导致不能删除
let ws = new WeakSet()
const obj1 = {name:"lilei"}
const obj2 = {age:12}
ws.add(obj1)
ws.add(obj2)
console.log(ws) // WeakSet{{...},{...}}

ws.delete(obj1)
console.log(ws) // WeakSet{{...}} // 曾经删除了{name:"lilei"}内容,次要就是因为对象属于援用类型,间接在delete写对象与前一个对象在堆内存中指向的不是同一个地址
console.log(ws.has(obj2)) // true 判断外部是否含有obj2对象,与map雷同,应用has函数
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

# Boolean

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title></title>
    <script>
        var b1 = new Boolean(1);
        console.log(b1);
        console.log(typeof(b1));//类型为对象
        console.log(Boolean(0));
        console.log(typeof(Boolean(0)));//为boolean基本类型
    </script>
</head>

<body>
</body>

</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# Date

Date表示日期对象,它常用的操作如下

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title></title>
    <script type="text/javascript" src="http://cdn.staticfile.org/moment.js/2.24.0/moment.js"> </script>
    <script>
        var date = new Date();

        document.write(date + "<br>");

        //返回当前date对象对应的时间本地字符串格式
        document.write(date.toLocaleString() + "<br>");

        //返回当前时间到1970年1月1日零点的毫秒值差
        document.write(date.getTime() + "<br>");

        //返回ISO8601格式时间
        document.write(moment().format("YYYY-MM-DDTHH:mm:ss.SSSZ"));
    </script>
</head>

<body>
</body>

</html>
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

# Math

Math表示数学对象,它不用创建直接使用。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title></title>
    <script>
        document.write(Math.PI + "<br>");
        //random():返回 0 ~ 1 之间的随机数。 含0不含1
        document.write(Math.random() + "<br>");
        //round(x):把数四舍五入为最接近的整数。
        document.write(Math.round(3.14) + "<br>");
        //ceil(x):对数进行向上舍入。
        document.write(Math.ceil(3.14) + "<br>");
        //floor(x):对数进行向下舍入。
        document.write(Math.floor(3.14) + "<br>");
        document.write(Math.PI + "<br>");

        /**
         * 取 1~100之间的随机整数
         *      1. Math.random()产生随机数:范围 [0,1)小数
         *      2. 乘以 100 --> [0,99.9999] 小数
         *      3. 舍弃小数部分 :floor --> [0,99] 整数
         *      4. +1 -->[0,99] 整数 [1,100]
         */
        var number = Math.floor((Math.random() * 100)) + 1;
        document.write(number + "<br>");
    </script>
</head>

<body>
</body>

</html>
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

# RegExp

RegExp表示正则表达式对象,用来定义字符串的组成规则。

  1. 单个字符:[],如: [a] [ab] [a-zA-Z0-9_]
    • 特殊符号代表特殊含义的单个字符:
      • \d:单个数字字符 [0-9]
      • \w:单个单词字符[a-zA-Z0-9_]
  2. 量词符号:
    • ?:表示出现0次或1次
    • *:表示出现0次或多次
    • +:出现1次或多次
    • {m,n}:表示 m<= 数量 <= n
      • m如果缺省: {,n}:最多n次
      • n如果缺省:{m,} 最少m次
  3. 开始结束符号
    • ^:开始
    • $:结束

实例如下:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title></title>
    <script>
        var reg = new RegExp("^\\w{6,12}$");
        var reg2 = /^\w{6,12}$/;

        console.log(reg)
        console.log(reg2)

        var username = "zhangsan";

        var flag = reg.test(username);
        console.log(flag);
    </script>
</head>

<body>
</body>

</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# Global

Global表示全局对象,这个Global中封装的方法不需要对象就可以直接调用。常用的操作有:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title></title>
    <script>
        var str = "http://www.baidu.com?wd=木叶清风";
        var encode = encodeURI(str);
        document.write(encode + "<br>");
        var s = decodeURI(encode);
        document.write(s + "<br>");


        var str1 = "http://www.baidu.com?wd=木叶清风";
        var encode1 = encodeURIComponent(str1);
        document.write(encode1 + "<br>");
        var s1 = decodeURIComponent(encode1);
        document.write(s1 + "<br>");


        var str = "a234abc";
        var number = parseInt(str);


        var a = NaN;
        //NaN参与的所有==判断都为false。
        document.write((a == NaN) + "<br>");
        document.write(isNaN(a));

        var jscode = "alert('hello')";
        eval(jscode); 
    </script>
</head>

<body>
</body>

</html>
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
37
38
39