JavaScript基础(四)

127 阅读28分钟

对象

1、引入定义

在JS中,对象是一组无序的相关属性和方法的集合,所有事物都是对象,例如字符串、数值、数组、函数等。

对象是由属性方法组成的。

  • 属性:事物的特征,在对象中用属性来表示
  • 方法:事物的行为,在对象中用方法来表示

2、创建对象

(1)字面量创建对象

对象字面量:就是花括号{}里面包含了表达这个具体事物(对象)的属性和方法

  • 里面的属性或者方法采用键值对的形式------ 键 属性名:值 属性值
  • 多个属性和方法用逗号隔开,最后一个不用逗号
  • 方法冒号后面跟着的是一个匿名函数

(2)调用对象:

调用对象的属性,我们采用

  • 对象名.属性名
  • 对象名['属性名']

调用对象的方法:

  • 对象名.方法名()一定要加()才算调用成功
     var obj = {
       name:111,
       age:222,
       sex:111,
       sayHi: function(){
         console.log('hello');
       }
     }
     console.log(obj.name);
     console.log(obj[sex]);

(3)变量、属性、函数、方法的区别

  • 变量和属性

相同点:都是用来存储数据的

不同点:

变量: 单独声明并赋值,使用的时候直接写变量名,单独存在

属性: 在对象里面是不需要声明的,使用的时候必须是对象名.属性

  • 函数和方法

相同点:都是实现某种功能,做某件事

不同点:

函数:函数是单独声明的并且调用的,调用方法:函数名(),也是单独存在的

方法:方法在对象里面,调用方法:对象名.方法名()

(4)new Object创建对象

和创建数组的方法类似(new Array)。

利用 等号 = 赋值的方法来添加对象的属性和方法

每个属性和方法之间用分号结束

     // new Object创建对象
     var obj = new Object();
     // 用等号为对象追加属性和方法
     obj.name = '111';
     obj.sayHi = function(){
       console.log('hi')
     }
     console.log(obj.name);
     obj.sayHi();

(5)构造函数创建对象

理解:

a.为什么使用构造函数

-----因为前两种创建对象的我方式一次只能创建一个对象

b.要创建大量的对象时要重复大量的相同代码,所以要用构造函数将对象中一些相同的属性和方法抽象出来封装到函数里面

c.构造函数里面封装的是对象

定义

构造函数:是一种特殊的函数,主要是用来初始化对象,即为对象成员变量赋初值,它总与new运算符一起使用。我们可以把对象中一些公共的方法和属性抽取出来,然后封装到这个函数中。

  • 构造函数不需要return就可以返回结果,构造函数名字首字母大写,调用构造函数必须要用new
  • 调用一次构造函数就创建了一个对象;
  • 属性和方法前面必须要加this

语法

    function 构造函数名(){
       this.属性 = 值;
       this.方法 = function(){}
     }
     new 构造函数名();

例子:

     // 构造函数名字首字母大写
     function Star(name,age,sex){
       // this.属性 = 值;
       this.name = name;
       this.sex = sex;
       this.age = age;
       this.sing = function(){
           consoloe.log('alalall')
       }  
     }
     var re = new Star('lll','222','333');
     // re是对象
     console.log(re);
     re.sing();
     // 构造函数不需要return就可以返回结果

构造函数和对象的区别

  • 对象是特指一个具体的事物
  • 构造函数是泛指某一大类
  • 通过new关键字创建对象的过程(利用构造函数创建对象的额过程)我们也称为对象实例化

new关键字的作用

  1. new构造函数可以在内存中创建了一个空的对象
  2. this就会指向刚才创建的空对象
  3. 执行构造函数里的代码,给这个空对象添加属性和方法
  4. 返回这个对象return(所以构造函数不需要)

3、遍历对象

for...in遍历对象,格式

 for (变量 in 对象){
     循环体
 }

使用for.....in循环里的循环变量习惯用key或k

     // 遍历对象
     var obj = {
       name: 111,
       age: 222,
       sex: 111,
       sayHi: function () {
         console.log('hello');
       }
     }
     for(var k in obj){
       // k变量 输出的是属性名,Obj[k]是属性值
       console.log(k);
       console.log(obj[k]);
     }

输出结果:

image.png

4、内置对象

(1)引入

JS中的对象分为三种:自定义对象、内置对象、浏览器对象,前两种对象是JS基础内容,属于ECMAScript;第三种对象是JS特有的,JS API会有讲解。

内置对象

  • 指JS语言自带的一些对象,这些对象供开发者使用,并提供了一些最常用的或是最基本而必要的功能(属性或方法)
  • 优点是帮助我们快速开发
  • JS提供了很多个内置对象:Math、Date、Array、String等

(2)查文档使用内置对象

途径MDN W3C

学习对象中的方法----注意点:

  • 参数的意义及类型,如果函数的括号中含有中括号,则表示中括号里的参数是可以省略的
  • 返回值及返回值类型
  • 查看案例,学习方法的属性

(3)Math对象

Math 是一个内置对象,它拥有一些数学常数属性和数学函数方法。不是一个函数对象。

Math用于 [数字]类型。它不支持 [BigInt]。

  • 描述

Math 与其他全局对象不同的是, 不是一个构造器(构造函数),不需要new来调用。Math 的所有属性与方法都是静态的。引用圆周率的写法是Math.PI ,调用正余弦函数的写法是Math.sin(x) , x是要传入的参数。Math的常量是使用 JavaScript 中的全精度浮点数来定义的。

  • Math的常用方法
     // 利用对象封装自己的数学对象,里面有PI最大值和最小值
     var myMath = {
       pI: 3.1415926,
       max: function () {
         var max = arguments[0];
         for (var i = 1; i < arguments.length; i++) {
           if(arguments(i) > max){
             max = arguments[i];
           }
         }
       },
       min: function () {
         var min = arguments[0];
         for (var i = 1; i < arguments.length; i++) {
           if(arguments(i) < min){
             min = arguments[i];
           }
         }
       }
     }
     console.log(myMath.PI);
     console.log(myMath.max(1,2,3,4,0));
     console.log(myMath.min(1,2,3,4,0));
  • 绝对值方法
     // 绝对值方法
     console.log(Math.abs(-1));
  • 三个取整方法
     // 1、Math.floor()  向下取整(往小取)
     console.log(Math.floor(1.23));
     console.log(Math.floor(1.9));
     // 2、Math.ceil()   向上取整(往大取)
     console.log(Math.ceil(1.2));
     console.log(Math.ceil(1.9));
     // Math.round()     四舍五入 
     console.log(Math.round(1.2));
     console.log(Math.round(1.9));
     console.log(Math.round(-1.1));//值为-1
     console.log(Math.round(-1.5));//值为-1
  • Math对象随机数方法, random()返回一个随机的小数

Math.random() 的返回值是一个浮点型伪随机数字,在(包括 0)和(不包括)之间。

  • 得到一个大于等于 0,小于 1 之间的随机数
 function getRandom() {
   return Math.random();
 }
  • 得到一个两数之间的随机数

这个例子返回了一个在指定值之间的随机数。这个值不小于 (有可能等于),并且小于(不等于)。min``max

 function getRandomArbitrary(min, max) {
   return Math.random() * (max - min) + min;
 }
  • 得到一个两数之间的随机整数

这个例子返回了一个在指定值之间的随机整数。这个值不小于 (如果 不是整数,则不小于 的向上取整数),且小于(不等于)。min``min``min``max

 function getRandomInt(min, max) {
   min = Math.ceil(min);
   max = Math.floor(max);
   return Math.floor(Math.random() * (max - min)) + min; //不含最大值,含最小值
 }
  • 得到一个两数之间的随机整数,包括两个数在内

上一个例子提到的函数 结果范围包含了最小值,但不含最大值。如果你的随机结果需要同时包含最小值和最大值,怎么办呢? 函数可以实现。getRandomInt()``getRandomIntInclusive()

 function getRandomIntInclusive(min, max) {
   min = Math.ceil(min);
   max = Math.floor(max);
   return Math.floor(Math.random() * (max - min + 1)) + min; //含最大值,含最小值
 }
     //随机点名
     function getRandomIntInclusive(min, max) {
       min = Math.ceil(min);
       max = Math.floor(max);
       return Math.floor(Math.random() * (max - min + 1)) + min; //含最大值,含最小值
     }
     var arr = ['小红','小李','小白','小张'];
     console.log(arr[getRandomIntInclusive(0, arr.length-1)]);
     // 猜数字游戏
     // 程序随机生成一个1~10之间的数字,并让用户输入一个数字
     function getRandom(min, max) {
       min = Math.ceil(min);
       max = Math.floor(max);
       return Math.floor(Math.random() * (max - min + 1)) + min; //含最大值,含最小值
     }
     var num = getRandom(1, 50);
     console.log(num);
     // while(true){}  死循环,猜对才能退出
     // for循环控制次数,达到次数没猜对就退出
     for (var i = 0; i <= 9; i++) {
       var selfNum = prompt('请输入1~50之间的整数');
       if (num > selfNum) {
         alert('数字小了,往大猜');
       } else if (num < selfNum) {
         alert('数字大了,往小猜');
       } else {
         alert('恭喜你,答对了');
         break;
       }
     }

(4)日期对象

Date()是一个构造函数,必须用new来调用创建日期对象

  • 获取当前时间必须实例化

如果没有输入任何参数,则 Date 的构造器会依据系统设置的当前时间来创建一个 Date 对象。

 var now = new Date();
 //没有参数,输出当前时间
  • Date()构造函数的参数

如果括号里有时间,就返回参数里的时间。数字型参数:如2019,01,20返回时间比参数大一个月

字符串参数2019-5-12019/5/1,正常返回

  • 以一个函数的形式来调用 对象(即不使用 new 操作符)会返回一个代表当前日期和时间的字符串。
     // 日期对象调用
     var now = new Date();
     console.log(now);
     var date1 = new Date('1990-07-09');
     console.log(date1);
     var date2 = new Date(2001,1,2);
     console.log(date2);
 ​
 ​
     var date = new Date();
     // date的常用方法
     console.log(date.getFullYear()); //返回当前日期的年 2019
     console.log(date.getMonth() + 1);//月份 返回的月份小一个月,所以月份要加1
     console.log(date.getDate());     //返回的是几号
     console.log(date.getDay());   //获取星期几(周日为0,到周六为6)
     console.log(date.getHours()); //获取当前小时
     console.log(date.getMinutes());//获取当前分钟
     console.log(date.getSeconds());//获取当前秒钟
 ​
 ​
     // 格式化日期---- 年 月 日 星期几
     var date = new Date();
     var year = date.getFullYear();
     var month = date.getMonth() + 1;
     var dates = date.getDate();
     var day = date.getDay();
     var arr = ['星期日','星期一','星期二','星期三','星期四','星期五','星期六'];
     console.log('今天是'+ year + '年' + month + '月' + dates + '日 ' + arr[day]);
 ​
     // 格式化日期---时 分 秒
     function getTime() {
       var date = new Date();
       var hour = date.getHours();
       var minute = date.getMinutes();
       var second = date.getSeconds();
       hour = hour < 10 ? '0' + hour : hour;
       minute = minute < 10 ? '0' + minute : minute;
       second = second < 10 ? '0' + second : second;
       return hour + ':' + minute + ':' + second;
     }
     console.log(getTime());

关于日期的案例

a.倒计时案例

输入的时间减去现在的时间就是剩余时间,即倒计时,但是不能用时分秒相减,比如05分减去25分结果为负数,所以要用时间戳来做,用户输入时间总的毫秒数减去现在时间的总的毫秒数,得到的就是剩余时间的毫秒数,再将剩余时间的毫秒数转化成天、时、分、秒(时间戳转化为时分秒)

转换公式:

  • 计算天数: d = (毫秒数/1000) / 60 / 60 / 24
  • 计算小时数:h = (毫秒数/1000) / 60 / 60 %24
  • 计算分钟数:m = (毫秒数/1000) % 60
  • 计算秒数:s = 毫秒数%1000
     function countDown(time){
       var nowTime = +new Date();
       var inputTime = +new Date(time);
       var times =(inputTime - nowTime)/1000; //将毫秒数换算成秒数
       var d = parseInt(times / 60 / 60 /24);//计算剩余天数
       d = d < 10? '0' + d: d;
       var h = parseInt(times / 60 / 60 % 24);//计算小时数
       h = h < 10? '0' + h: h;
       var m = parseInt(times / 60 % 60); //计算分钟数
       m = m < 10? '0' + m: m;
       var s = parseInt(times % 60); //计算秒数
       s = s < 10? '0' + s: s;
       return d + '天' + h + '时' + m + '分' + s + '秒'; 
     }
     var date = new Date();
     console.log(date);
     console.log(countDown('2022-12-23 12:03:00'));

(5)数组对象

a.数组回顾

     // 数组对象
     // 1、利用数组字面量创建数组
     var arr = [1, 2, 3];
     // 2、利用new Array创建空数组
     var arr1 = new Array(2);  //表示数组长度为2,有俩个空的数组元素
     console.log(arr1);
     var arr2 = new Array(2, 3);//等价于[2,3],表示数组有2个数组元素是2和3
     console.log(arr2);
 ​
     function reverse(arr) {
        var newArr = [];
        for (var i = arr.length - 1; i >= 0; i--) {
           newArr[newArr.length] = arr[i];
        }
       return newArr;
      }
      console.log(reverse([1, 2, 3, 4, 5]));

b.检测是否为数组的两种方法

1.instanceof

用来检测 constructor.prototype 是否存在于参数 object 的原型链上;

语法:

 object instanceof constructor

参数:

object 某个实例对象

constructor 某个构造函数

2.Array.isArray()

Array.isArray() 用于确定传递的值是否是一个 Array

 Array.isArray([1, 2, 3]);  // true
 Array.isArray({foo: 123}); // false
 Array.isArray('foobar');   // false
 Array.isArray(undefined);  // false

语法:

 Array.isArray(value)

参数:

value 需要检测的值。

返回值:

如果值是 Array,则为 true;否则为 false

 // 下面的函数调用都返回 true
 Array.isArray([]);
 Array.isArray([1]);
 Array.isArray(new Array());
 Array.isArray(new Array('a', 'b', 'c', 'd'))
 Array.isArray(new Array(3));
 // 鲜为人知的事实:其实 Array.prototype 也是一个数组。
 Array.isArray(Array.prototype);
 ​
 // 下面的函数调用都返回 false
 Array.isArray();
 Array.isArray({});
 Array.isArray(null);
 Array.isArray(undefined);
 Array.isArray(17);
 Array.isArray('Array');
 Array.isArray(true);
 Array.isArray(false);
 Array.isArray(new Uint8Array(32))
 Array.isArray({ __proto__: Array.prototype });

案例:

     // 监测是否为数组
     // (1) instanceof 运算符,它可以监测是否为数组
     function reverse(arr) {
       // if (arr instanceof Array) {
       if (Array.isArray(arr)) {
         var newArr = [];
         for (var i = arr.length - 1; i >= 0; i--) {
           newArr[newArr.length] = arr[i];
         }
         return newArr;
       } else {
         return 'error,不是数组类型'
       }
     }
     console.log(reverse(5));
     console.log(reverse([1, 2, 3, 4, 5]));
     // (2) Array.isArray(参数); H5新增的方法,ie9以上版本支持
     var arr = [];
     var obj = {};
     console.log(Array.isArray(obj));
     console.log(Array.isArray(arr));
     console.log(obj instanceof Array);
     console.log(arr instanceof Array);

instanceof VS isArray(不懂,随手粘贴的)

当检测 Array 实例时,Array.isArray 优于 instanceof,因为 Array.isArray 能检测 iframes

 const iframe = document.createElement('iframe');
 document.body.appendChild(iframe);
 xArray = window.frames[window.frames.length-1].Array;
 const arr = new xArray(1,2,3); // [1,2,3]
 ​
 // 正确检查 Array
 Array.isArray(arr);  // true
 // Considered harmful, because doesn't work through iframes
 arr instanceof Array; // false

c.添加删除数组元素

1.Array.prototype.pop()

pop() 方法从数组中删除最后一个元素,并返回该元素的值。此方法会更改数组的长度

语法

 pop()

返回值

从数组中删除的元素(当数组为空时返回undefined)。

描述

pop 方法从一个数组中删除并返回最后一个元素

pop 方法有意具有通用性。该方法和 call()apply() 一起使用时,可应用在类似数组的对象上。pop 方法根据 length 属性来确定最后一个元素的位置。如果不包含 length 属性或 length 属性不能被转成一个数值,会将 length 置为 0,并返回 undefined

如果你在一个空数组上调用 pop(),它将返回 undefined

2.Array.prototype.unshift()

unshift() 方法将一个或多个元素添加到数组的开头,并返回该数组的新长度

语法

 unshift(element0)
 unshift(element0, element1)
 unshift(element0, element1, /* … ,*/ elementN)

参数列表

  • elementN要添加到数组开头的元素。

返回值

返回调用方法对象的新 length 属性值。

描述

unshift() 方法会在调用它的类数组对象的开始位置插入给定的值。

Array.prototype.push()unshift() 具有相似的行为,但其会在数组的末尾插入元素。

unshift() 特意被设计成具有通用性;这个方法能够通过 callapply 方法作用于类数组对象上。不过对于没有 length 属性(代表从 0 开始的一系列连续的数字属性的最后一个)的对象,调用该方法可能没有任何意义。

注意,如果传入多个参数,它们会被以块的形式插入到对象的开始位置,它们的顺序和被作为参数传入时的顺序一致。于是,传入多个参数调用一次 unshift(),和传入一个参数调用多次 unshift()(例如,循环调用),它们将得到不同的结果。例如:

 let arr = [4, 5, 6];
 ​
 arr.unshift(1, 2, 3);
 console.log(arr);
 // [1, 2, 3, 4, 5, 6]
 ​
 arr = [4, 5, 6]; // 重置数组
 arr.unshift(1);
 arr.unshift(2);
 arr.unshift(3);
 console.log(arr);
 // [3, 2, 1, 4, 5, 6]
    var arr1 = new Array(5,4,3,2,1);
    console.log(arr1.unshift([1,2,9]));
    console.log(arr1);

输出结果:

image.png
3.Array.prototype.push()

push() 方法将一个或多个元素添加到数组的末尾,并返回该数组的新长度。

语法

 push(element0)
 push(element0, element1)
 push(element0, element1, /* … ,*/ elementN)

参数

  • elementN 被添加到数组末尾的元素。

返回值

当调用该方法时,新的 length 属性值将被返回。

描述

push 方法将值追加到数组中。

push 方法具有通用性。该方法和 call()apply() 一起使用时,可应用在类似数组的对象上。push 方法根据 length 属性来决定从哪里开始插入给定的值。如果 length 不能被转成一个数值,则插入的元素索引为 0,包括 length 不存在时。当 length 不存在时,将会创建它。

唯一的原生类数组(array-like)对象是 Strings,尽管如此,它们并不适用该方法,因为字符串是不可改变的。

添加元素到数组

下面的代码创建了 sports 数组,包含两个元素,然后又把两个元素添加给它。total 变量为数组的新长度值。

 var sports = ["soccer", "baseball"];
 var total = sports.push("football", "swimming");
 ​
 console.log(sports);
 // ["soccer", "baseball", "football", "swimming"]
 ​
 console.log(total);
 // 4

合并两个数组

该示例使用 apply() 添加第二个数组的所有元素。

注意当第二个数组 (如示例中的 moreVegs) 太大时不要使用这个方法来合并数组,因为事实上一个函数能够接受的参数个数是有限制的。具体可以参考 apply()

 var vegetables = ['parsnip', 'potato'];
 var moreVegs = ['celery', 'beetroot'];
 ​
 // 将第二个数组融合进第一个数组
 // 相当于 vegetables.push('celery', 'beetroot');
 Array.prototype.push.apply(vegetables, moreVegs);
 ​
 console.log(vegetables);
 // ['parsnip', 'potato', 'celery', 'beetroot']

像数组一样使用对象

如上所述,push 是特意设计为通用的,我们可以使用它来获得便利。正如下面的例子所示,Array.prototype.push 可以在一个对象上工作。注意,我们没有创建 一个数组来存储对象的集合。相反,我们将该集合存储在对象本身上,并使用在 Array.prototype.push 上使用的 call 来调用该方法,使其认为我们正在处理数组,而它只是像平常一样运作,这要感谢 JavaScript 允许我们建立任意的执行上下文。

 var obj = {
     length: 0,
 ​
     addElem: function addElem (elem) {
         // obj.length is automatically incremented
         // every time an element is added.
         [].push.call(this, elem);
     }
 };
 ​
 // Let's add some empty objects just to illustrate.
 obj.addElem({});
 obj.addElem({});
 console.log(obj.length);
 // → 2

注意,尽管 obj 不是数组,但是 push 方法成功地使 obj 的 length 属性增长了,就像我们处理一个实际的数组一样。

4.Array.prototype.shift()

shift() 方法从数组中删除第一个元素,并返回该元素的值。此方法更改数组的长度。

 shift()

返回值

从数组中删除的元素; 如果数组为空则返回undefined

描述

shift 方法移除索引为 0 的元素 (即第一个元素),并返回被移除的元素,其他元素的索引值随之减 1。如果 length 属性的值为 0 (长度为 0),则返回 undefined

shift 方法并不局限于数组:这个方法能够通过 callapply 方法作用于类似数组的对象上。但是对于没有 length 属性(从 0 开始的一系列连续的数字属性的最后一个)的对象,调用该方法可能没有任何意义。

Array.prototype.pop() 有着和 shift相似的行为,但是是作用在数组的最后一个元素上的。

移除数组中的一个元素

以下代码显示了删除其第一个元素之前和之后的 myFish 数组。它还显示已删除的元素:

 let myFish = ['angel', 'clown', 'mandarin', 'surgeon'];
 ​
 console.log('调用 shift 之前:' + myFish);
 // "调用 shift 之前:angel,clown,mandarin,surgeon"
 ​
 var shifted = myFish.shift();
 ​
 console.log('调用 shift 之后:' + myFish);
 // "调用 shift 之后:clown,mandarin,surgeon"
 ​
 console.log('被删除的元素:' + shifted);
 // "被删除的元素:angel"
 var myFish = ['angel', 'clown', 'mandarin', 'surgeon'];
 ​
 console.log('myFish before:', JSON.stringify(myFish));
 // myFish before: ['angel', 'clown', 'mandarin', 'surgeon']
 ​
 var shifted = myFish.shift();
 ​
 console.log('myFish after:', myFish);
 // myFish after: ['clown', 'mandarin', 'surgeon']
 ​
 console.log('Removed this element:', shifted);
 // Removed this element: angel

在 while 循环中使用 shift()

shift() 方法经常用于 while loop 的环境中.。下例中每个循环将要从一个数组中移除下一项元素,直至它成为空数组。

 var names = ["Andrew", "Edward", "Paul", "Chris" ,"John"];
 while( (i = names.shift()) !== undefined ) {
     console.log(i);
 }
 // Andrew, Edward, Paul, Chris, John
5.Array.prototype.slice()

slice() 方法返回一个新的数组对象,这一对象是一个由 beginend 决定的原数组的浅拷贝(包括 begin,不包括end)。原始数组不会被改变。

语法:

 slice()
 slice(start)
 slice(start, end)

参数:

  • begin 可选

    提取起始处的索引(从 0 开始),从该索引开始提取原数组元素。如果该参数为负数,则表示从原数组中的倒数第几个元素开始提取,slice(-2) 表示提取原数组中的倒数第二个元素到最后一个元素(包含最后一个元素)。如果省略 begin,则 slice 从索引 0 开始。如果 begin 超出原数组的索引范围,则会返回空数组。

  • end 可选

    提取终止处的索引(从 0 开始),在该索引处结束提取原数组元素。slice 会提取原数组中索引从 beginend 的所有元素(包含 begin,但不包含 end)。slice(1,4) 会提取原数组中从第二个元素开始一直到第四个元素的所有元素(索引为 1, 2, 3 的元素)。如果该参数为负数,则它表示在原数组中的倒数第几个元素结束抽取。 slice(-2,-1) 表示抽取了原数组中的倒数第二个元素到最后一个元素(不包含最后一个元素,也就是只有倒数第二个元素)。如果 end 被省略,则 slice 会一直提取到原数组末尾。如果 end 大于数组的长度,slice 也会一直提取到原数组末尾。

返回值:

一个含有被提取元素的新数组。

描述:

slice 不会修改原数组,只会返回一个浅复制了原数组中的元素的一个新数组。原数组的元素会按照下述规则拷贝:

  • 如果该元素是个对象引用(不是实际的对象),slice 会拷贝这个对象引用到新的数组里。两个对象引用都引用了同一个对象。如果被引用的对象发生改变,则新的和原来的数组中的这个元素也会发生改变。
  • 对于字符串、数字及布尔值来说(不是 StringNumber 或者 Boolean 对象),slice 会拷贝这些值到新的数组里。在别的数组里修改这些字符串或数字或是布尔值,将不会影响另一个数组。

如果向两个数组任一中添加了新元素,则另一个不会受到影响。

6.Array.prototype.splice()

splice() 方法通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组。

语法:

 splice(start)
 splice(start, deleteCount)
 splice(start, deleteCount, item1)
 splice(start, deleteCount, item1, item2, itemN)

参数

  • start

    指定修改的开始位置(从 0 计数)。如果超出了数组的长度,则从数组末尾开始添加内容;如果是负值,则表示从数组末位开始的第几位(从 -1 计数,这意味着 -n 是倒数第 n 个元素并且等价于 array.length-n);如果负数的绝对值大于数组的长度,则表示开始位置为第 0 位。

  • deleteCount 可选

    整数,表示要移除的数组元素的个数。如果 deleteCount 大于 start 之后的元素的总数,则从 start 后面的元素都将被删除(含第 start 位)。如果 deleteCount 被省略了,或者它的值大于等于array.length - start(也就是说,如果它大于或者等于start之后的所有元素的数量),那么start之后数组的所有元素都会被删除。如果 deleteCount 是 0 或者负数,则不移除元素。这种情况下,至少应添加一个新元素。

  • item1, item2, ... 可选

    要添加进数组的元素,从start 位置开始。如果不指定,则 splice() 将只删除数组元素。

返回值

被删除的元素组成的一个数组。如果只删除了一个元素,则返回只包含一个元素的数组。如果没有删除元素,则返回空数组。

描述

如果添加进数组的元素个数不等于被删除的元素个数,数组的长度会发生相应的改变。

d.翻转数组和数组排序

1.reverse()方法

定义:

reverse() 方法反转数组中元素的顺序,改变原始数组。

语法:

 array.reverse()

返回值:

数组,表示反转后的数组。

2.sort()方法

定义

sort() 方法对数组的项目进行排序。

排序顺序可以是按字母或数字,也可以是升序(向上)或降序(向下)。

默认情况下,sort() 方法将按字母和升序将值作为字符串进行排序。

这适用于字符串("Apple" 出现在 "Banana" 之前)。但是,如果数字按字符串排序,则 "25" 大于 "100" ,因为 "2" 大于 "1"。

正因为如此,sort() 方法在对数字进行排序时会产生不正确的结果。

您可以通过提供“比较函数”来解决此问题(请参阅下面的“参数值”)。

语法

 array.sort(compareFunction)

参数值

参数描述
compareFunction可选。定义替代排序顺序的函数。该函数应返回负值、零值或正值,具体取决于参数,例如:function(a, b){return a-b}sort() 方法比较两个值时,将值发送给比较函数,根据返回的(负、零、正)值对值进行排序。举例:比较 40 和 100 时,sort() 方法调用比较函数(40,100)。该函数计算 40-100,并返回 -60(负值)。sort 函数会将 40 排序为小于 100 的值。

返回值

Array 对象,其中的项目已排序。

注释: sort() 方法会改变原始数组。

     // 1、反转数组
     var arr = [1 , 22, 3 , 44];
     arr.reverse();
     console.log(arr);
     // 2、排序
     var arr1 = [1,9,3,4];
     arr1.sort();
     console.log(arr1);
     // sort()不能对两位数进行升序排序
     arr.sort(function(a,b){
       // return a-b;  按照升序排列
       return b-a;  //按照降序排列
     });  
     console.log(arr);

e.数组索引方法

1.Array.prototype.indexOf()

indexOf() 方法返回在数组中可以找到给定元素的第一个索引,如果不存在,则返回 -1。

语法

 indexOf(searchElement)
 indexOf(searchElement, fromIndex)

参数

  • searchElement

    要查找的元素。

  • fromIndex 可选

    开始查找的位置。如果该索引值大于或等于数组长度,意味着不会在数组里查找,返回 -1。如果参数中提供的索引值是一个负值,则将其作为数组末尾的一个抵消,即 -1 表示从最后一个元素开始查找,-2 表示从倒数第二个元素开始查找,以此类推。注意:如果参数中提供的索引值是一个负值,并不改变其查找顺序,查找顺序仍然是从前向后查询数组。如果抵消后的索引值仍小于 0,则整个数组都将会被查询。其默认值为 0。

返回值

首个被找到的元素在数组中的索引位置; 若没有找到则返回 -1

描述

indexOf 使用全等运算(与 ===,或称为三等号运算符的方法相同)判断 searchElement 与数组中包含的元素之间的关系。

示例

使用 indexOf()

以下例子使用 indexOf() 方法确定多个值在数组中的位置。

 const array = [2, 9, 9];
 array.indexOf(2);     // 0
 array.indexOf(7);     // -1
 array.indexOf(9, 2);  // 2
 array.indexOf(2, -1); // -1
 array.indexOf(2, -3); // 0

找出指定元素出现的所有位置

 const indices = [];
 const array = ['a', 'b', 'a', 'c', 'a', 'd'];
 const element = 'a';
 let idx = array.indexOf(element);
 while (idx !== -1) {
   indices.push(idx);
   idx = array.indexOf(element, idx + 1);
 }
 console.log(indices);
 // [0, 2, 4]

判断一个元素是否在数组里,不在则更新数组

 function updateVegetablesCollection (veggies, veggie) {
   if (veggies.indexOf(veggie) === -1) {
     veggies.push(veggie);
     console.log(`New veggies collection is: ${veggies}`);
   } else {
     console.log(`${veggie} already exists in the veggies collection.`);
   }
 }
 ​
 const veggies = ['potato', 'tomato', 'chillies', 'green-pepper'];
 ​
 updateVegetablesCollection(veggies, 'spinach');
 // New veggies collection is: potato,tomato,chillies,green-pepper,spinach
 updateVegetablesCollection(veggies, 'spinach');
 // spinach already exists in the veggies collection.
2.Array.prototype.lastIndexOf()

概述

lastIndexOf() 方法返回指定元素(也即有效的 JavaScript 值或变量)在数组中的最后一个的索引,如果不存在则返回 -1。从数组的后面向前查找,从 fromIndex 处开始。

语法

 lastIndexOf(searchElement)
 lastIndexOf(searchElement, fromIndex)

参数

  • searchElement

    被查找的元素。

  • fromIndex 可选

    从此位置开始逆向查找。默认为数组的长度减 1(arr.length - 1),即整个数组都被查找。如果该值大于或等于数组的长度,则整个数组会被查找。如果为负值,将其视为从数组末尾向前的偏移。即使该值为负,数组仍然会被从后向前查找。如果该值为负时,其绝对值大于数组长度,则方法返回 -1,即数组不会被查找。

返回值

数组中该元素最后一次出现的索引,如未找到返回 -1。

描述

lastIndexOf 使用严格相等 (en-US)(strict equality,即 ===)比较 searchElement 和数组中的元素。

下例使用 lastIndexOf 定位数组中的值。

 var array = [2, 5, 9, 2];
 var index = array.lastIndexOf(2);
 // index is 3
 index = array.lastIndexOf(7);
 // index is -1
 index = array.lastIndexOf(2, 3);
 // index is 3
 index = array.lastIndexOf(2, 2);
 // index is 0
 index = array.lastIndexOf(2, -2);
 // index is 0
 index = array.lastIndexOf(2, -1);
 // index is 3

例子:查找所有元素

下例使用 lastIndexOf 查找到一个元素在数组中所有的索引(下标),并使用 push 将所有添加到另一个数组中。

 var indices = [];
 var array = ['a', 'b', 'a', 'c', 'a', 'd'];
 var element = 'a';
 var idx = array.lastIndexOf(element);
 ​
 while (idx != -1) {
   indices.push(idx);
   idx = (idx > 0 ? array.lastIndexOf(element, idx - 1) : -1);
 }
 ​
 console.log(indices);
 // [4, 2, 0];

注意,我们要单独处理idx==0时的情况,因为如果是第一个元素,忽略了fromIndex参数则第一个元素总会被查找。这不同于indexOf方法。

注:原英文是针对使用三元操作符语句的作用进行说明的: idx = (idx > 0 ? array.lastIndexOf(element, idx - 1) : -1); idx > 0时,才进入 lastIndexOf 由后往前移一位进行倒查找;如果idx == 0则直接设置idx = -1,循环while (idx != -1)就结束了。

f.数组转换为字符串

1.Array.prototype.join()

join() 方法将一个数组(或一个类数组对象)的所有元素连接成一个字符串并返回这个字符串,用逗号或指定的分隔符字符串分隔。如果数组只有一个元素,那么将返回该元素而不使用分隔符。

语法

 join()
 join(separator)

参数

  • separator 可选

    指定一个字符串来分隔数组的每个元素。如果需要,将分隔符转换为字符串。如果省略,数组元素用逗号(,)分隔。如果 separator 是空字符串(""),则所有元素之间都没有任何字符。

返回值

一个所有数组元素连接的字符串。如果 arr.length 为 0,则返回空字符串。

描述

所有数组元素被转换成字符串并连接到一个字符串中。如果一个元素是 undefinednull,它将被转换为空字符串,而不是字符串 "undefined""null"

Array.prototype.toString() 会在内部访问 join 方法,不带参数。覆盖一个数组实例的 join 也将覆盖它的 toString 行为。

当在稀疏数组上使用时,join() 方法迭代空槽,就像它们的值为 undefined 一样。

join() 方法是通用的。它只要求 this 值具有 length 属性和整数键的属性。

在稀疏数组上使用 join()

join() 将空槽视为 undefined,并产生额外的分隔符:

 console.log([1, , 3].join()); // '1,,3'
 console.log([1, undefined, 3].join()); // '1,,3' 

在非数组对象上调用 join()

join() 方法读取 thislength 属性,然后访问每个整数索引。

 const arrayLike = {
   length: 3,
   0: 2,
   1: 3,
   2: 4,
 };
 console.log(Array.prototype.join.call(arrayLike));
 // 2,3,4
 console.log(Array.prototype.join.call(arrayLike, "."));
 // 2.3.4
2.Array.prototype.toString()

toString() 方法返回一个字符串,表示指定的数组及其元素。

描述

Array对象覆盖了 ObjecttoString 方法。对于数组对象,toString 方法在内部调用 join()方法拼接数组中的元素并返回一个字符串,其中包含用逗号分隔的每个数组元素。如果 join 方法不可用,或者它不是一个函数,将使用 Object.prototype.toString代替,返回 [object Array]

3.Array.prototype.toLocaleString()

toLocaleString() 返回一个字符串表示数组中的元素。数组中的元素将使用各自的 toLocaleString 方法转成字符串,这些字符串将使用一个特定语言环境的字符串(例如一个逗号 ",")隔开。

语法

 toLocaleString();
 toLocaleString(locales);
 toLocaleString(locales, options);

参数

返回值

表示数组元素的字符串。

使用localesoptions

数组中的元素将会使用各自的 toLocaleString 方法:

  • Object: [Object.prototype.toLocaleString()]
  • Number: [Number.prototype.toLocaleString()]
  • Date: [Date.prototype.toLocaleString()]

总是在prices数组中显示字符串和数字的货币符号:

 var prices = ['¥7', 500, 8123, 12];
 prices.toLocaleString('ja-JP', { style: 'currency', currency: 'JPY' });
 ​
 // "¥7,¥500,¥8,123,¥12"

(6)字符串对象

1.基本包装类型

基本包装类型就是把简单数据类型包装成为复杂数据类型,这样基本数据类型就有了属性和方法。

     // 基本包装类型
     var str = 'andy';
     console.log(str.length);

基本数据类型没有属性和方法,但是JS会把基本数据类型包装成为负责数据类型,执行过程如下

     // 对象才有属性和方法;复杂数据类型才有属性和方法
     // 简单数据类型为什么会有length属性呢?
     // 基本包装类型:就是把简单数据类型包装成了复杂数据类型
     // 执行过程:
     // (1)把简单数据类型包装成了复杂数据类型
     var temp = new String(andy);
     // (2)把临时变量的值给str
     str = temp;
     // (3)销毁这个临时变量
     temp = null;

2.字符串不可变

指的是值不可变,虽然看上去可以改变内容,但其实是地址改变了,内存中新开辟了一个内存空间

所以不要大量的拼接字符串

3.根据字符返回位置

字符串所有的方法,都不会修改字符串本身(字符串是不可变的),操作完成会返回一个新的字符串

     // 根据字符返回位置
     // 查找字符串中出现该字母的位置以及次数
     // str.indexOf('要查找的字符',开始查找的起始位置);同数组对象一样使用字符串对象
     var str1 = 'abcoefoxyozzopp'
     var newArr = [];
     var index = str1.indexOf('o');
     while (index !== -1) {
       newArr.push(index);
       //index++;
       //index = str1.indexOf('o',index);
       //9、10行等效为12行或13行代码  
       //index = str1.indexOf('o',index+1);
       index = str1.indexOf('o',++index);
       //这里不可以换为index++,因为index++表达式的值不自增,++index表达式值自增  
     }
     console.log(newArr);
     // ['red','blue','red','green','pink','red'],求red出现的位置和次数
     var str = ['red','blue','red','green','pink','red'];
     var newArr = [];
     var num = 0;
     var index = str.indexOf('red')
     while(index !== -1){
       newArr.push(index);
       index = str.indexOf('red',++index)
     }
     console.log(newArr);

4.根据位置返回字符

方法名说明使用
charAt(index)返回指定位置的字符(index字符串的索引号)str.charAt(0)
charCodeAt(index)获取指定位置处字符的ASCII码(index索引号)str.charCodeAt(0)
str[index]获取指定位置处字符HTML5,IE8+支持和charAt()等效

(ASCII码:A--97,a--65,可以根据ASII码判断用户按键)

  //有一个对象,来判断是否有该属性 对象['属性名']
     // var o = {
     // }
     // if(o['sex']){
     //   console.log('里面有该属性');
     // }else{
     //   console.log('里面没有该属性');
     // }
     // 判断一个字符串'abcoefoxyozzopp'中出现次数最多的字符,并统计其次数
     // 遍历字符串,将字母作为属性存入对象中,属性值为字母出现的次数
     // o['age']调用对象属性的方法
     var o = {
 ​
     }
     var str = 'abcoefoxyozzopp';
     for (var i = 0; i < str.length; i++) {
       var chars = str.charAt(i);
       // 由于chars是字符串,则不能用o.a的写法调用对象属性,要使用o['a']
       if (o[chars]) {
         o[chars]++;
       } else {
         o[chars] = 1;
       }
     }
     console.log(o);
     // 利用for in遍历对象
     var max = 0;
     var ch = '';
     for (var k in o) {
       // k得到的是属性名
       // o[k]得到的是属性值
       if (o[k] > max) {
         max = o[k];
         // k出了for循环就不起作用了,所以要用ch来存字符串
         ch = k;
       }
     }
     console.log(max);
     console.log('出现次数最多的字符是' + ch);

5.字符串操作方法

方法名说明
concat(str1,str2.str3.....)concat()方法用于连接两个或多个字符串。拼接字符串,等效于+,+更常用
substring(start,end)从start位置开始,截取到end位置,end取不到,基本和slice相同,但是不接受负值
substr(start,length)从start位置开始(索引号),length取得个数
slice(start,end)从start位置开始,截取到end位置,end取不到(他们俩都是索引号)
replace(rgExp,replaceText)rgExp是被替换的字符,可以是正则表达式或字符串。replaceText是替代查找到的字符串
split(separator,howmany)把字符串分割成为字符串数组。separator,从该参数指定得地方开始分割。howmany,该参数可指定返回数组的最大长度
toUpperCase()将调用该方法的字符串值转为小写形式,并返回。toLowerCase 不会影响字符串本身的值。
toLowerCase()将调用该方法的字符串转为大写形式并返回(如果调用该方法的值不是字符串类型会被强制转换)
     // 字符串操作方法
     // 1、concat('字符串1','字符串2'......)
     var str = 'andy';
     console.log(str.concat('red','blue'));
     // 2、substr('截取的起始位置','截取几个字符')
     var str1 = '改革春风吹满地';
     console.log(str1.substr(2,2));//春风
     // 3、替换字符 replace('被替换的字符','替换为的字符'),只会替换第一个字符
     var str2 = 'andyccab';
     console.log(str2.replace('a','b'));
     // 有一个字符串'abcoefoxyozzopp',要求把里面所有的o替换为*
     var str3 = 'abcoefoxyozzopp';
     // replace替换第一个字符,
     while(str3.indexOf('o')!== -1){
       str3 = str3.replace('o','*');
     }
     console.log(str3);
     // 2、字符转换为数组 split('分隔符'),join把数组转换为字符串
     var str4 = 'red,pink,blue';
     console.log(str4.split(','));
     var str5 = 'red&pink&blue';
     console.log(str5.split('&'));

image.png

5、简单类型与复杂类型

简单类型又叫做基本数据类型或者值类型,复杂类型又叫做引用类型。

  • 值类型∶简单数据类型/基本数据类型,在存储时变量中存储的是值本身,因此叫做值类型

string , number , boolean , undefined , null

注意:如果有变量打算存储为对象,但是暂时没想好放什么值,这个时候就给null

  • 引用类型∶复杂数据类型,在存储时变量中存储的仅仅是地址(引用),因此叫做引用数据类型。

通过new关键字创建的对象(系统对象、自定义对象),如Object、Array、Date等

  • 堆栈空间分配区别:
    1、栈(操作系统)︰由操作系统自动分配释放存放函数的参数值、局部变量的值等。其操作方式类似于数据结构中的栈。简单数据类型存放到栈里面
    2、堆(操作系统)︰存储复杂类型(对象),一般由程序员分配释放,若程序员不释放,由垃圾回收机制回收。复杂数据类型存放到堆里面

简单数据类型是存放在栈里面里面直接开辟一个空间存放的是值

复杂数据类型首先在栈里面存放地址十六进制表示―然后这个地址指向堆里面的数据

(1)简单数据类型传参

函数的形参也可以看做是一个变量,当我们把一个值类型变量作为参数传给函数的形参时,其实是把变量在栈空间里的值复制了一份给形参,那么在方法内部对形参做任何修改,都不会影响到的外部变量

     // 简单数据类型null返回的是一个空的对象,object
     var timer = null;
     console.log(typeof timer); //object
     // 如果有变量打算存储为对象,但是暂时没想好放什么值,这个时候就给null
     function fn(a) {
       a++;
       console.log(a);//11
     }
     var x = 10;
     fn(x);
     console.log(x);//10

(2)复杂数据类型传参

函数的形参也可以看做是一个变量,当我们把引用类型变量传给形参时,其实是把变量在栈空间里保存的堆t址复制给了形参,形参和实参其实保存的是同一个堆地址,所以操作的是同一个对象。

     // 复杂类型传参
     function Person(name){
       this.name = name;
     }
     //f1(p)是把p的地址赋值给了x
     function f1(x){
       console.log(x.name);
       x.name = 'zhang';
       console.log(x.name);
     }
     var p = new Person('li');  
     console.log(p.name); //li
     f1(p);//li  zhang
     console.log(p.name); //zhang