• js数据结构


    数据结构

    所谓数据结构,就是计算机存储和组织数据的方式。说得通俗一点,主要就是指将数据以什么样 的结构存储到计算机里面。在程序里面,最为常见的数据结构,就是数组,这种结构将多个数据 有序的排列在一起,形成了一个组合。除了数组以外,集合,映射等ES6新增加的数据结构

    创建数组的方式大致可以分为两种:字面量创建数组和使用构造函数创建数组。

    1. 字面量创建数组

    2. let arr = [];

    3. 构造函数创建数组

    let arr = new Array();

    1. 先声明再赋值

    let arr = [];

    arr[0] = 1;

    arr[1] = 2;

    arr[2] = 3;

    注意下标是从o开始的。

    2. 声明时直接赋值

    let arr = [1,2,3,4,5];

    需要注意的是我们可以在数组的任意位置进行赋值,数组的长度会自动改变,空的位置使用

    undefined来进行填充

    let arr = [];

    arr[0] = 1;

    arr[4] = 10;

    console.log(arr);

    什么是集合

    在ES6标准制定以前,可选的数据结构类型有限,可以说只有数组这种数据结构。而数组使用的 又是数值型索引,因而经常被用于来模拟队列和栈的行为。但是如果需要使用非数值型索引,就 会用非数组对象创建所需的数据结构,而这就是Set集合与后面一节要介绍的Map映射的早期实 现。

    Set集合是一种无重复元素的列表,这是这种数据结构的最大的一个特点。

    要创建一个集合,方法很简单,直接使用new就可以创建一个Set对象。如果想要集合在创建时 就包含初始值,那么我们可以传入一个数组进去。

    let s1 = new Set();

    let s2 = new Set([1,2,3]);

    console.log(s1);//Set {}

    console.log(s2);//Set { 1, 2, 3 }

    4-3-3给集合添加值

    使用add()方法可以给一个集合添加值,由于调用add()方法以后返回的又是一个Set对象,所 以我们能连续调用add()方法进行值的添加,这种像链条一样的方法调用方式被称为链式调 用。

    let s1 = new Set();

    s1.add(1);

    console.log(s1);//Set { 1 }

    s1.add(2).add(3).add(4);

    console.log(s1);

    //Set { 1, 2, 3, 4 } 我们还可以直接将一个数组传入add()方法里面

    let s1 = new Set();

    s1.add([1,2,3]);

    console.log(s1);

    //Set { [ 1, 2, 3 ] }

    let s1 = new Set([1,2,3]);

    console.log(s1);//Set { 1, 2, 3 } console.log(s1.size);//3

    调用add()方法时传入数组,就是作为Set对象的一个元素

    let s1 = new Set();

    s1.add([1,2,3]);

    console.log(s1);//Set { [ 1, 2, 3 ] } console.log(s1.size);//1

    在Set对象中,不能够添加相同的元素,这是很重要的一个特性

    let s1 = new Set();

    s1.add(1).add(2).add(2).add(3);

    console.log(s1);

    //Set { 1, 2, 3 }

    1. size属性获取元素个数

    let s1 = new Set([1,2,3]);

    console.log(s1.size);//3

    2. 使用hasO方法来查看一个集合中是否包含某一个值

    let s1 = new Set([1,2,3]);

    console.log(s1.has(1));//true

    3. 删除集合值

    使用delete删除Set对象里面的某一个元素

    let s1 = new Set([1,2,3]);

    s1.delete(2);

    console.log(s1);//Set { 1, 3 }

    //没有的元素也不会报错

    s1.delete("2");

    console.log(s1);//Set { 1, 3 }

    如果要一次性删除所有的元素,可以使用clear方法

    let s1 = new Set([1,2,3]);

    s1.clear()

    console.log(s1);//Set {}

    遍历集合

    集合也是可以枚举的,我们同样可以使用for-o f来对集合进行遍历,如下:

    let s = new Set([1,2,3,4,5]);

    for(let i of s){ console.log(i);

    }

    // 1

    // 2

    // 3

    // 4

    // 5


    除此之外,我们也可以使用集合里面自带的keys() , values()以及ent ries()方法来对集合 进行遍历。顺便要说一下的是,在集合里面键和值是相同的。

    keys()方法遍历集合的键

    let s = new Set(["Bill","Lucy","David"]); for(let i of s.keys()){

    console.log(i);

    }

    // Bill

    // Lucy

    // David

    values()方法遍历集合的值

    let s = new Set(["Bill","Lucy","David"]); for(let i of s.values()){

    console.log(i);

    }

    // Bill

    // Lucy

    // David

    ent ries()方法同时遍历集合的键与值

    let s = new Set(["Bill","Lucy","David"]); for(let i of s.entries()){

    console.log(i);

    }

    // [ 'Bill', 'Bill' ]

    // [ 'Lucy', 'Lucy' ]

    // [ 'David', 'David' ]

    集合转数组

    将集合转为数组,最快的方法就是使用前面所讲过的扩展运算符,如下:

    let s1 = new Set([1,2,3]);

    console.log(s1);//Set { 1, 2, 3 }

    let arr = [...s1]; console.log(arr);//[ 1, 2, 3 ]

    除此之外,我们还可以使用Arra y对象所提供的from。方法来进行转换

    let s1 = new Set([1,2,3]); console.log(s1);//Set { 1, 2, 3 }

    let arr = Array.from(s1); console.log(arr);//[ 1, 2, 3 ]

    前面我们有提到过,Set对象里面是不能够存放相同的元素的,利用这个特性,我们可以快速的 为数组去重,如下:

    let arr = [1,2,2,3,4,3,1,6,7,3,5,7];

    let s1 = new Set(arr);

    let arr2 = [...s1]; console.log(arr2);//[ 1, 2, 3, 4, 6, 7, 5 ]

    什么是内存泄漏?

    —个程序里面保留着已经不能在内存中访问的值时,就会发生内存泄露,也就是说占着空间却没 用,造成内存的浪费。

    例如:

    let arr = [1,2,3]; arr = null;

    断开了arr对1, 2, 3的引用,现在1, 2, 3在内存里面已经是垃圾了。内存泄露会逐渐减少全部 可用内存,导致程序和系统的速度变慢甚至崩溃

    那么怎样才能清空这些没用的数据呢?例如上例中的1, 2, 3。事实上在JavaScript中采用的是 动态内存管理技术,比如垃圾回收机制,会自动从内存中删除不再被程序需要的东西。而有些编 程语言,例如C++,则是需要程序员手动的管理内存,在某些东西完成任务之后,将其从内存中 删除。

    那么,集合的问题就在于即使失去了引用,也不会被垃圾回收,这个时候我们可以使用弱集合来 避免这种状况。创建弱集合使用new运算符和WeakSet()

    let weak = new WeakSet();

    弱集合无法添加基本数据类型,也就是说无法像集合那样添加简单值进去。

    let weak = new WeakSet();

    weak.add(1);

    //TypeError: Invalid value used in weak set

    除了这个限制以外,弱集合和普通集合还有一些细微的区别,例如无法在创建弱集合时传入一个 数组进行初始化。不过弱集合也拥有has() , add() , delete()等方法。

    let arr = [1,2,3,4,5];

    let weak = new WeakSet(arr);

    //TypeError: Invalid value used in weak set

    //无法在创建弱集合时传入一个数组进行初始化

    还需要注意一点的是,弱集合是对对象的弱引用,所以不能访问对象里面的值列表。这使得弱集 合看上去像是空的,但是并不是空的,证明如下:

    let weak = new WeakSet();

    let arr = [1,2,3];

    weak.add(arr);

    console.log(weak);//WeakSet {}

    console.log(weak.has(arr));//true

    console.log(s1.has("1"));//false

    使用new关键字与Map()构造函数,就可以创建一个空的m ap对象。如果要向Map映射中添加 新的元素,可以调用set()方法并分别传入键名和对应值作为两个参数。如果要从集合中获取 信息,可以调用get()方法。

    let m = new Map();

    m.set("name","xiejie");

    m.set("age",18);

    console.log(m);

    //Map { 'name' => 'xiejie', 'age' => 18 }

    console.log(m.get("name"));

    //xiejie

    在对象中,无法用对象作为对象属性的键名。但是在Map映射中,却可以这样做,可以这么说, 在Map映射里面可以使用任意数据类型来作为键。

    let m = new Map();

    m.set({},"xiejie"); m.set([1,2,3],18);

    m.set(3581,18);

    console.log(m);

    //Map { {} => 'xiejie', [ 1, 2, 3 ] => 18, 3581 => 18 }传入数组来初始化Map映射 可以向Map构造函数传入一个数组来初始化Map映射,这一点同样与Set集合相似。数组中的每 个元素都是一个子数组,子数组中包含一个键值对的键名与值两个元素。因此,整个Map映射中 包含的全是这样的两个元素的二维数组

    let arr = [["name","xiejie"],["age",18]];

    let m = new Map(arr);

    console.log(m);

    //Map { 'name' => 'xiejie', 'age' => 18 }

    Map结构转为数组结构,比较快速的方法还是使用前面介绍过的扩展运算符...。

    let arr = [["name","xiejie"],["age",18]];

    let m = new Map(arr);

    console.log([...m.keys()]);//[ 'name', 'age' ]

    console.log([...m.values()]);//[ 'xiejie', 18 ]

    console.log([...m.entries()]);//[ [ 'name', 'xiejie' ], [ 'age', 18 ] ]

    console.log([...m]);//[ [ 'name', 'xiejie' ], [ 'age', 18 ] ] 或者使用Array对象的from。方法

    let arr = [["name","xiejie"],["age",18]];

    let m = new Map(arr);

    console.log(Array.from(m));

    //[ [ 'name', 'xiejie' ], [ 'age', 18 ] ]

    函数

    函数,是可以通过名称来引用,并且就像自包含了一个微型程序的代码块。利用函数,我们可以 实现对代码的复用,降低代码的重复,并且让代码更加容易阅读。在JavaScript中,函数显得尤 为的重要。因为函数在JavaScript中是一等公民,可以像参数一样传入和返回。所以说函数是 JavaScript中的一个重点,同时也是一个难点。

    为什么需要函数

    首先我们来看一下为什么需要函数。函数最大的好处就是可以对代码实现复用。相同的功能不用 再次书写,而是只用书写一次就够了。这其实就是编程里面所谓的DRY原则

    所谓DRY原则,全称为Don‘t repeat yourself,翻译成中文就是不要重复你自己。什么意思 呢?也就是说一个程序的每个部分只被编写一次,这样做可以避免重复,不需要保持多个代 码段的更新和重复。

    并且,我们可以把函数看作是一个暗箱,不需要知道函数的内部是怎么实现的,只需要知道函数 的功能,参数以及返回值即可。

    声明函数的方式
    在JavaScript中,声明函数的方式有多种,这里我们先来介绍这3种声明函数的方式:字面量声明 函数,函数表达式声明函数以及使用构造器方式来声明一个函数。

    1. 字面量声明函数

    这种方式是用得最为广泛的一种方式,使用关键字function来创建一个函数,具体的语法如 下:

    function函数名(形式参数){

    //函数体

    }

    函数名:就是我们调用函数时需要书写的标识符

    形式参数:简称形参,是调用函数时需要接收的参数

    实际参数:简称实参,是调用函数时实际传递过去的参数

    function test(name){

    console.log("Hello,"+name);

    }

    test("xiejie");//Hello,xiejie

    2. 函数表达式声明函数

    第二种方式是使用函数表达式来进行声明,具体的语法如下:

    let 变量 =function(){

    //函数体

    }

    函数表达式示例:

    let test = function(name){

    console.log("Hello,"+name);

    } test("xiejie");//Hello,xiejie

    我们也可以将一个带有名字的函数赋值给一个变量。这样的声明方式被称之为命名式函数 表达式

    示例如下:

    let test = function saySth(name){

    console.log("Hello,"+name);

    }

    test("xiejie");//Hello,xiejie

    注意:虽然这种方式的函数表达式拥有函数名,但是调用的时候还是必须要通过变量名来调 用,而不能够使用函数名来进行调用。

    函数的调用

    函数的调用在前面介绍函数声明的时候也已经见到过了,就是写上函数名或者变量名,后面加上 —对大括号即可。需要注意的是,一般来讲函数表示的是一个动作,所以在给函数命名的时候, —般都是以动词居多。

    还一个地方需要注意,那就是如果要调用函数,那么就必须要有括号。这个括号要么在函数名后 面,要么在变量名后面,这样才能够将调用函数后的执行结果返回。如果缺少了括号,那就只是 引用函数本身。

    let test = function(){ console.log("Hello");

    }

    let i = test;//没有调用函数,而是将test函数赋值给了i i();//Hello

    函数的返回值

    函数的返回值的关键字为ret urn。代表要从函数体内部返回给外部的值,示例如下:

    let test = function(){ return "Hello";

    }

    let i = test();

    console.log(i);//Hello

    即使不写return ,函数本身也会有返回值undefined 例如:

    let test = function(){

    console.log("Hello");

    }

    let i = test();//Hello

    console.log(i);//undefined

    需要注意的是,retu rn后面的代码是不会执行的,因为在函数里面一旦执行到ret urn ,整个 函数的执行就结束了。

    let test = function(){ return 1; console.log("Hello");

    }

    let i = test();

    console.log(i);//1

    retu rn关键字只能返回一个值,如果想要返回多个值,可以考虑返回一个数组。

    函数的参数

    函数的参数可以分为两种,一种是实际参数,另外一种是形式参数。这个我们在前面已经介绍过 了。接下来我们来详细看一下形式参数。形式参数简称形参,它就是一种变量,但是这种变量只 能被函数体内的语句使用,并在函数调用时被赋值。JavaScript中的形参的声明是不需要添加关 键字的,如果加上关键字反而会报错

    示例:

    function test(let i){ console.log(i);

    }

    test(5);

    //SyntaxError: Unexpected identifier

    JavaScript里面关于函数的形参,有以下几个注意点: 1•参数名可以重复,同名的参数取最后一个参数值

    function test(x,x){

    console.log(x);

    }

    test(3,5);//5

    2•即使函数声明了参数,调用时也可以不传递参数值

    function test(x){ console.log(x);

    }

    test();//undefined

    3•调用函数时可以传递若干个参数值给函数,而不用管函数声明时有几个参数

    function test(x){

    console.log(x);//1

    }

    test(1,2,3);

    那么,这究竟是怎么实现的呢?为什么实参和形参可以不用一一对应呢?

    实际上,当一个函数要被执行的时候,系统会在执行函数体代码前做一些初始化工作,其中之一 就是为函数创建一个arguments的伪数组对象。这个伪数组对象将包含调用函数时传递的所有的 实际参数。因此,arguments的主要用途是就是用于保存传入到函数的实际参数的。

    下面的例子演示了通过arguments伪数组对象来访问到所有传入到函数的实参

    function test(x){

    for( let i=0;i<arguments.length;i++){

    console.log(arguments[i]);

    }

    }

    test(1,2,3);

    // 1

    // 2

    // 3

    所谓伪数组对象,就是长得像数组的对象而已,但是并不是真的数组,我们可以证明这一点

    function test(x){

    ar guments .push( 100); //针对伪数组对象使用数组的方法

    }

    test(1,2,3);

    //TypeError: arguments.push is not a function

    不定参数

    不定参数是从ES6开始新添加的功能,在最后一个形式参数前面添加3个点,会将所有的实参放 入到一个数组里面,示例如下:

    function test(a,...b){

    console.log(a);//1

    console.log(b);//[2,3]

    test(1,2,3);

    这里的不定参数就是一个真正的数组,可以使用数组的相关方法

    function test(a,...b){ console.log(a);//1 console.log(b);//[2,3] b.push(100);

    console.log(b);//[ 2, 3, 100 ]

    } test(1,2,3);

    还有一点需要注意的是,不定参数都是放在形式参数的最后面,如果不是放在最后,则会报错。

    function test(...a,b){ console.log(a); console.log(b);

    } test(1,2,3);

    //SyntaxError: Rest parameter must be last formal parameter

    默认参数

    从ES6开始,书写函数的时候可以给函数的形式参数一个默认值。这样如果在调用函数时没有传 递相应的实际参数,就使用默认值。如果传递了相应的实际参数,则使用传过去的参数。

    function test(name = "world"){ console.log("Hello,"+name);

    } test("xiejie");//Hello,xiejie test();//Hello,world

    如果参数是一个数组,要为这个数组设置默认值的话,写法稍微有些不同,如下:

    let fn = function([a = 1,b = 2] = []){ console.log(a,b);

    }

    fn(); // 1 2

    fn([3,4]); // 3 4

    包括后面我们要介绍的对象,也是可以设定默认值的,但是写法和上面类似,如下:

    let fn = function({name = 'xiejie',age = 18} = {}){ console.log(name,age);

    }

    fn(); // xiejie 18

    fn({name:"song",age:20}); // song 20

     

     

     

  • 相关阅读:
    h5 喜帖
    h5 录音
    UglifyJS-- 对你的js做了什么
    SimpleCaptcha生成图片验证码内容为乱码
    Spring.profiles多环境配置最佳实践
    eclipse maven 导出项目依赖的jar包
    cygwin下切换到其他磁盘
    chrome 浏览器的插件权限有多大?
    windows系统tomcat日志输出至catalina.out配置说明
    Windows10远程报错:由于CredSSP加密Oracle修正
  • 原文地址:https://www.cnblogs.com/akangwx0624/p/11149258.html
Copyright © 2020-2023  润新知