JavaScript基础(2)

342 阅读25分钟

数组

所谓数组(Array),就是将多个元素(通常是同一类型)按一定顺序排列放到一个集合中,那么这个集合我们就称之为数组。
数组的元素类型不限制,长度可以动态的调整。

// 创建一个空数组
var arr = [];
// 创建包含多个数据的数组,数据类型是不限制
var arr2 = [1,true,false,null,undefined,"haha",[7,8],9,10];
// 获取 arr2 中下标为 0 和 1 的项
console.log(arr2[0]);
console.log(arr2[1]);
// 更改数组中某一项的值
arr2[4] = 5;
// 获取数组的长度
console.log(arr2.length);
// 获取数组最后一项的值
console.log(arr2[arr2.length - 1]);
// 给length属性赋值,强制更改数组的长度
// 大于下标,多出来的项为空。小于下标,后面的数据项会被直接删除,且不可逆
arr2.length = 12;// 大于最大下标10,arr2[10]、arr2[11]为空
console.log(arr2);
arr2.length = 10;// 小于最大下标12,arr2[10]、arr2[11]数据被删除
console.log(arr2);
// 增加一个大于最大下标的项,强制增加数组的长度
arr2[14] = 13;

数组遍历

var arr = [45,56,76,88,89,90,100,34,56];
// 给数组中每一项数据加 5
for (var i = 0; i < arr.length ; i++) {
  arr[i] += 5;
}
console.log(arr);

函数

函数(function),也叫作功能、方法,函数可以将一段代码一起封装起来,被封装起来的函数具备某一项特殊的功能。
函数的作用就是封装一段代码,将来可以重复使用。

// 函数必须先定义才能使用
// 函数名命名规则:可以使用字母、数字、下划线、$,数字不能作为开头,区分大小写,不能使用关键字,和变量命名规则一样
// 函数声明
function fun() {
  console.log(1);
  console.log(2);
  console.log(3);
}
// 函数调用
fun();

函数的参数

函数预留了一个接口,专门用于让用户自定义内容,使函数发生一些执行效果变化。
接口:就是函数的参数,函数参数的本质就是变量,可以接收任意类型的数据,导致函数执行结果根据参数不同,结果也不同。
实参和形参解释如下:

// 定义一个求和函数,传入两个数据
// 参数:传两个参数,数据类型为数字
// 功能:得到两个数字之和
function sum(a,b) {
  console.log(a + b);
}
// 调用函数
sum(3,4);

函数的返回值

// 使用返回值,制作函数运行结束后的
function sum(a,b) {
  return a + b;
}
// 将返回值赋值给变量
var num = sum(3,4);
console.log(num);
// 将返回值赋值给函数的实参
console.log(sum(2,sum(3,4)));

函数表达式

函数达式是函数定义的另外一种方式。
定义方法:就是将函数的定义、匿名函数赋值给一个变量。
函数定义赋值给一个变量,相当于将函数整体矮化成了一个表达式。
匿名函数:函数没有函数名。
调用函数表达式,方法是给变量名加()执行,不能使用函数名加()执行。

// 定义一个函数表达式
var foo = function fun() {
  console.log(1);
};
var foo2 = function () {
  console.log(2);
};
// 调用函数式,只能用变量名调用,函数名调用不成功
foo();
foo2();
fun(); // 调用不成功

函数的数据类型

函数是一种单独的数据类型Function。由于函数是一种数据类型,可以参与其他程序。
例如,可以把函数作为另一个函数的参数,在另一个函数中调用。或者,可以把函数可以作为返回值从函数内部返回。

// 函数是一种数据类型,可以当成其他函数的参数
setInterval(function(){
  console.log(1);
},1000);
// 将函数当成另一个函数的返回值
function fn(b) {
  var a = 10;
  return function () {
    alert(a + b);
  };
}

函数的arguments对象

JavaScript中,arguments对象是比较特别的一个对象,实际上是当前函数的一个内置属性。也就是说所有函数都内置了一个arguments对象,arguments对象中存储了传递的所有的实参。arguments是一个伪数组,因此及可以谨行遍历。
函数的实参个数和形参个数可以不一致,所有的实参都会存储在函数内部的arguments类数组对象中。

// 定义一个函数
function sum(a,b) {
  return a + b;
}
// 调用函数的时候,实参的个数可以与形参不同
console.log(sum(1,2));
console.log(sum(1));
console.log(sum(1,2,3,4));
//函数内部有一个 arguments 对象,会接收所有的实参
function fun() {
  console.log(arguments);
  console.log(arguments.length);
  // 使用数组的遍历方法可以获取每一项实参
  for (var i = 0 ; i <= arguments.length - 1 ; i++) {
    console.log(arguments[i]);
  }
}
// 调用函数
fun(1,2,3,4,5,6,7);

函数递归

函数内部可以通过函数名调用函数自身的方式,就是函数递归现象。
递归的次数太多容易出现错误:超出计算机的计算最大能力。
更多时候,使用递归去解决一些数学中的现象。
例如可以输出斐波那契数列的某一项的值。

// 菲波那切数列
// 参数:正整数
// 返回值:对应的整数位置的菲波那切数列的值
function fibo(a) {
  if (a === 1 || a === 2) {
    return 1;
  } else {
    return fibo(a - 1) + fibo(a - 2);
  }
}
// 调用函数
console.log(fibo(1));
console.log(fibo(2));
console.log(fibo(3));
console.log(fibo(4));
console.log(fibo(5));
console.log(fibo(6));

作用域

作用域:变量可以起作用的范围。 如果变量定义在一个函数内部,只能在函数内部被访问到,在函数外部不能使用这个变量,函数就是变量定义的作用域。
任何一对花括号{}中的结构体都属于一个块,在这之中定义的所有变量在代码块外都是不可见的,我们称之为块级作用域。
在es5之前没有块级作用域的的概念,只有函数作用域,现阶段可以认为JavaScript没有块级作用域。

全局变量和局部变量

局部变量:定义在函数内部的变量,只能在函数作用域内部被访问到,在外面没有定义的。
全局变量:从广义上来说,也是一种局部变量,定义在全局的变量,作用域范围是全局,在整个js程序任意位置都能够被访问到。变量退出作用域之后会销毁,全局变量关闭网页或浏览器才会销毁。

参数和函数的作用域

函数的参数本质是一个变量,也有自己的作用域,函数的参数也是属于函数自己内部的局部变量,只能在函数内部被使用,在函数外面没有定义。

// 函数的参数也是局部变量
function fun(a) {
  a = 2;
  console.log(a);//  在函数内部可以调用参数a
}
// 调用函数
fun(1);
//console.log(a);//  在函数外部不能调用参数a,会报错

函数也有自己的作用域。

// 函数也有自己的作用域
function outer() {
  var a = 1;
  function inner() {
    console.log(2);
  }
  // 函数内部调用子函数inner()才能成功
  inner();
}
// 调用函数
outer();
//inner();//  函数外部不能调用子函数inner(),会报错

作用域链和遮蔽效应

  • 作用域链 只有函数可以制造作用域结构,那么只要是代码,就至少有一个作用域,即全局作用域。凡是代码中有函数,那么这个函数就构成另一个作用域。如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域。
    将这样的所有的作用域列出来,可以有一个结构:函数内指向函数外的链式结构。就称为作用域链。
  • 遮蔽效应 程序在遇到一个变量时,使用时作用域查找顺序,不同层次的函数内都有可能定义相同名字的变量,一个变量在使用时,会优先从自己所在层作用域查找变量,如果当前层没有变量定义会按照顺序从本层往外依次查找,直到找到第一个变量定义。整个过程中会发生内层变量遮蔽外层变量的效果,叫做“遮蔽效应”。
// 全局作用域
var a = 1;
// 创建函数
function outer() {
  var a = 2;
  // 内部函数
  function inner() {
    var a = 3;
    console.log(a);// 首先会从本级链查找到a=3,遮蔽了外级链的a=2和a=1, 输出为3,
  }
  inner();
  console.log(a);// 首先会从本级链查找到a=2,遮蔽了外级链的a=1,输出为2
}
// 调用
outer();

在函数中不写关键字var的影响

在函数内部想要定义新的变量,如果不加关键字var,相当于定义的全局变量。如果全局也有相同的标识符,会被函数内部的变量影响,局部变量污染全局变量。
注意:每次定义变量时都必须写var关键字,否则就会定义在全局,可能污染全局。

var a = 1;
function fun() {
 a = 2;// 没有关键字var,为全局变量
 console.log(a);// 输出为2
}
fun();
console.log(a);// 输出为2, 而不是1,因为被fun()运行后污染

预解析和声明提升

JavaScript代码的执行是由浏览器中的JavaScript解析器来执行的。JavaScript解析器执行JavaScript代码的时候,分为两个过程:预解析过程和代码执行过程。
预解析过程:
1,把变量的声明提升到当前作用域的最前面,只会提升声明,不会提升赋值。
2.把函数的声明提升到当前作用域的最前面,只会提升声明,不会提升调用。
3.先提升var,再提升function。

变量声明提升

JavaScript的执行过程:在预解析之后,根庭新的代码顺序,从上往下按照既定规律执行js代码。
在预解析过程中,所有定义的变量,都会将声明的过程提升到所在的作用域最上面,在将来的代码执行过程中,按照先后顺序会先执行被提升的声明变量过程。
提升过程中,只提升声明过程,不提升变量賦值,相当于变量定义未赋值,变量内存储undefined值。
因此,在js中会出现一种现象,在前面调用后定义的变量,不会报错,只会使用 undefined值。

var a = 1;
function fun() {
 console.log(a);//a在本级作用域链有声明(声明无论在本级何处,预处理时都会将其放在本级作用域的最前面),所以使用本级作用域的a,但调用在赋值之前,所以会输出undefined
 var a = 0;
}
fun();

函数声明提升

定义的函数会将声明作用域最上面,将来的代码执行过程中,按照先后顺序会先执行被提升的函数声明过程。
在预解析之后的代码执行过程中,函数定义过程已经在最开始就会执行,一旦函数定义成功,后续就可以直接调用函数。
因此,在js中会出现一种现象,在前面调用后定义的函数,不会报错,而且能正常执行函数内部的代码。

// 先调用函数
fun();
// 定义函数
function fun() {
  console.log(2);
}

提升顺序

预解析过程中,先提升var变量声明,再提升function函数声明。 假设出现变量名和函数名相同,那么后提升的函数名标识符会覆盖先提升的变量名,那么在后续代码中出现调用标识符时,内部是函数的定义过程,而不是undefined。
如果调用标识符的过程在源代码函数和变量定义后面,相当于函数名覆盖了一次变量名,结果在执行到变量赋值时,又被新值盖了函数的值,那么在后面再次调用标识符,用的就是变量存的新值。
建议:不要书写相同的标识符给变量名或函数名,避免出现覆盖。

var fun = "haha";
// 定义函数
function fun() {
  console.log(2);
}
fun();// 报错类型错误,fun is not a function

函数表达式的提升

在预解析过程中,函数表达式进行的是变量声明提升,而不是函数声明提升。提升后变量内部存的是一个undefinedo在前面进行函数方法调用,数据类型会提示错误。
建议:定义函数时,最好使用function关键字定义方式,这样函数声明提升可以永远生效。

console.log(foo);// 输出undefined
foo();// 报错类型错误,foo is not a function
// 函数表达式进行的是变量声明提升
var foo = function () {
  console.log(3);
};

函数声明提升的应用

函数声明提升可以用于调整代码的顺序,将大段的定义过程放到代码最后,但是不影响代码执行效果。

IIFE自调用函数

IIFE:immediately-invokedfunctionexpression,叫做即时调用的函数表达式,也叫做自调用函数,表示函数在定义时就立即调用。 函数调用方式:函数名或函数表达式的变量名后面加()运算符。 函数名定义的形式不能实现立即执行自调用,函数使用函数表达式形式可以实现立即执行,原因是因为函数表达式定义过程中,将一个函数矮化成了一个表达式,后面加()运算符就可以立即执行。 启发:如果想实现IIFE,可以想办法将函数矮化成表达式。

函数矮化成表达式的方法

函数要矮化成表达式,可以让函数参与一些运算,也就是说给函数前面加一些运算符。 数学运算符:+-() 逻辑运算符:! 非运算 IIFE结构可以关住函数的作用域,在结构外面是不能调用函数的。 IIFE最常用的是()运算符,而且函数可以不写函数名,使用匿名函数。

// 常用的 IIFE 结构
(function (a) {
  console.log(a);
})(4);
// 关键字定义的方式,不能立即执行
//function fun() {
//  console.log(1);
//}();
// 函数表达式方式,可以在定义时被立即执行
var foo = function fun() {
  console.log(2);
}();
// 通过在函数前面添加操作符,可以将函数矮化成表达式
+ function fun() {
  console.log(1);
}();// -、()、!操作符也可以

对象

JavaScript中的对象:
JavaScript中的对象其实就是生活中对象的一个抽象。
JavaScript的对象是无序属性的集合,其属性可以包含基本值、对象或函数。对象就是一组没有顺序的值。我们可以把JavaScript中的对象想象成键值对,其中值可以是数据和函数。
对象的行为和特征:
特征——在对象中用属性表示;
行为——在对象中用方法表示。

对象字面量

创建一个对象最简单的方式是使用对象字面量赋值给变量。类似数组。 对象字面量语法:{}
内部可以存放多条数据,数据与数据之间用逗号分隔,最后一个后面不要加逗号。
每条数据都是有属性名和属性值组成,键值对写法:k:v
k:属性名
v:属性值,可以是任意类型的数据,比如简单类型数据、函数、对象。 区分属性和方法:

  • 属性:对象的描述性特征,一般是名词,相当于定义在对象内部的变量。
  • 方法:对象的行为和功能,一般是动词,定义在对象中的函数。
// 通过对象字面量方式创建一个对象
var person1 = {
  name : "zs",
  age : 18,
  sex : "male",
  sayHi : function () {
    console.log(this.name + "向你说您好");// 内部调用使用this.属性名调用
  }
};

对象数据的调用和更改

// 调用对象的属性和方法
console.log(person1.name);
console.log(person1.age);
console.log(person1.sex);
person1.sayHi();
// 中括号调用方法
console.log(person1["name"]);
person1["sayHi"]();
person1.sayHi();
// 更改数据
person1.age = 19;
// 添加新数据
person1.weight = 140;
// 删除属性
delete person1.sex;
console.log(person1);

其他创建对象的方式

new Object()构造函数创建对象

Object()构造函数,是一种特殊的函数。主要用来在创建对象时初始化对象,即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中。

  • 构造函数用于创建一类对象,首字母要大写。
  • 构造函数要和new一起使用才有意义。没有new,构造函数就跟普通函数一样,而且没有意义。
    new 在执行时会做四件事:
  • new会在内存中创建一个新的空对象
  • new会让this指向这个的对象
  • 执行构造函数目的:给这个新对象加属性和方法
  • new会返回这个新对象
// new Object() 方法创建
var person1 = new Object();   //创建了一个新的空的对象
// 添加属性和方法
person1.name = "zs";
person1.age = 18;
person1.sex = true;
person1.sayHi = function () {
  console.log("你好");
};

工厂函数方法创建对象

如果要创建多个类似的对象,可以将newObject()过程封装到一个函数中,将来调用函数就能创建一个对象,相当于一个生产对象的函数工厂,用来简化代码。

// 工厂方法就是相当于对 new Object() 方法的一个封装
function createPerson(name,age,sex) {
  // 创建一个空对象
  var person = new Object();
  // 添加属性和方法,属性可以接受参数的值
  person.name = name;
  person.age = age;
  person.sex = sex;
  person.sayHi = function () {
    console.log("hello");
  };
  // 将对象作为函数的返回值
  return person;
}
// 想创建一个对象,可以调用工厂函数
var p1 = createPerson("zs",18,true);
var p2 = createPerson("ls",19,false);
// 输出
console.log(p1);
console.log(p2);

自定义构造函数方法创建对象

比工厂方法更加简单。
自定义一个创建具体对象的构造函数,函数内部不需要new一个构造函数的过程,直接使用this代替对象进行属性和方法的书写,也不需要return一个返回值。
使用时,利用new关键字调用自定义的构造函数即可。
注意:构造函数的函数名首字母需要大写,区别于其他普通函数名。

// 自己定义一个构造函数
function Person(name,age,sex) {
  // 不需要使用 new 一个新对象
  // 用 this 替代将来创建的新对象
  this.name = name;
  this.age = age;
  this.sex = sex;
  this.sayHi = function () {
    console.log("hello");
  };
  // 不需要添加 return
}
// 用 new 关键字调用构造函数
var p1 = new Person("zs",18,true);

对象遍历方法

// 通过对象字面量方式创建一个对象
var person1 = {
  name : "zs",
  age : 18,
  sex : "male",
  sayHi : function () {
    console.log(this.name + "向你说您好");
  }
};
// 遍历对象
for (var k in person1) {
  // k 存储的是每一条数据的属性名或者方法名
  console.log(k + "属性的属性值为" + person1[k]);
}

简单数据类型和复杂数据类型

简单数据类型和复杂数据类型的区别: 简单数据类型又叫做值类型,复杂类型又叫做引用类型 值类型:简单数据类型,基本数据类型,在存储时,变量中存储的是值本身,因此叫做值类型。 引用类型:复杂数据类型,在存储时,变量中存储的仅仅是地址(引用),因此叫做引用数据类型。

// 基础数据类型
var a = 5;
var b = a;  //将 a 内部存储的数据 5 复制了一份给 b
a = 10;
console.log(a);
console.log(b);
// 复杂数据类型
var p1 = {
  name : "zs",
  age : 18,
  sex : "male"
};
var p = p1;  //p1 将内部存储的指向对象原型的地址复制给了 p
// 两个变量之间是一个联动的关系,一个变化,会引起另一个变化
p.name = "ls";
console.log(p);
console.log(p1);
// 数组和函数存储在变量中时,也是存储的地址
var arr = [1,2,3,4];
var arr2 = arr;
arr[4] = 5;
console.log(arr);
console.log(arr2);

内置对象

JavaScript的对象包含三种:自定义对象、内置对象、浏览器对象(BOM中) ECMAscript的对象:自定义对象、内置对象 使用一个内置对象,只需要知道对象中有哪些成员,有什么功能,直接使用。 需要参考一些说明手册W3C/MDN。MDN的更加详尽。

console.log(Math);

Math对象

Math对象它具有数学常数和函数的属性和方法,我们可以直接进行使用。根据数学相关的运算来找Math中的成员(求绝对值,取整)。

创建数组对象的两种方式

数组也是对象, 创建数组对象有以下两种方式:

  • 字面量方式[]
arr = ['12', 'Jack', 'Rose'];
  • new Array构造函数方法。
// 数组也是对象,可以通过构造函数生成
// 空数组
var arr1 = new Array();
// 添加数据,直接传参数
var arr2 = new Array(1,2,3);
var arr3 = new Array("zs","ls","ww");
// 检测数组的数据类型
console.log(typeof(arr));// 输出Object
console.log(typeof(arr3));// 输出Object
var a = {};
// 检测某个实例对象是否属于某个对象类型
console.log(arr1 instanceof Array);// 输出true
console.log(arr2 instanceof Array);// 输出true
console.log(a instanceof Array);// 输出false
console.log(fun instanceof Function);// 输出true
function fun () {
  console.log(1);
}

数组对象的常用方法

toString() 将数组转换成字符串,以英文逗号连接

arr = ['1', '2', '3'];
console.log(arr.toString());

join() 通过参数作为连字符将数组中的每一项用连字符连成一个完整的字符串

// 字面量方法
var arr = [1,2,3,4,5,6,7,8,9,10];
// 转字符串方法
var str = arr.join();// 不传参,默认以英文逗号连接
console.log(str);
str = arr.join("");// 传空字符串,使数组内容无间隔连接成字符串
console.log(str);

首尾数据操作:
push() 在数组耒尾添加一个或多个元素,并返回数组操作后的长度
pop() 删除数组最后一项,返回删除项
shift() 删除数组第一项,返回删除项
unshift()在数组开头添加一个或多个元素,并返回数组的新长度

// 字面量方法
var arr = [1,2,3,4];
// 将数组的第一项移动到最后一项
// 删除第一项
// 将删除的项添到最后一项
arr.push(arr.shift());
console.log(arr);
arr.push(arr.shift());
console.log(arr);
arr.push(arr.shift());
console.log(arr);
arr.push(arr.shift());
console.log(arr);

concat()方法
将两个数组合并成一个新的数组,原数组不受影响。参数位置可以是一个数组字面量、数组变量、零散的值。

slice(start,end)方法
从当前数组中截取一个新的数组,不影响原来的数组,返回一个新的数组,包含从start到end(不包括该元素)的元素。
参数区分正负,正值表示下标位置,负值表示从后面往前数第几个位置,参数可以只传递一个,表示从开始位置截取到字符串结尾。

// 字面量方法
var arr = [1,2,3,4,5,6,7,8,9,10];
// 合并方法
// 参数:数组、数组的变量、零散的
// 返回值:一个新的拼接后的数组
var arr1 = arr.concat([5,6,7]);
var ar = [8,9,10]
arr1 = arr.concat(ar);
arr1 = arr.concat(11,12,13);
console.log(arr);
console.log(arr1);
    
// 拆分方法
// 参数为正
arr1 = arr.slice(3,7);
// 参数为负
arr1 = arr.slice(-7,-1);
// 只书写一个参数
arr1 = arr.slice(7);
console.log(arr);
console.log(arr1);

splice和位置方法
删除、插入、替换:
splice(index,howmany,elementl,element2,...)
用于插入、删除或替换数组的元素
index:删除元素的开始位置
howmany:删除元素的个数,可以是0
element1,element2...:要替换的新的数据。
位置方法: indexOf()查找数据在数组中最先出现的下标
lastlndexOf()查找数据在数组中最后一次出现的下标
注意:如果没找到返回-1

// 字面量方法
var arr = [1,2,3,4,5,6,7,8,9,10];
// 删除功能,传前两个参数
console.log(arr.splice(2,5));
console.log(arr);
// 替换功能,传3个及以上的参数
arr.splice(2,5,"haha","hello");
console.log(arr);
// 插入功能,传3个及以上的参数,但是第二个参数必须为0
arr.splice(2,0,"hello");
console.log(arr);

// 查找某个元素在数组中从前往后第一次 出现位置的下标
console.log(arr.indexOf(4));
// 查找某个元素在数组中从前往后最后一次出现位置的下标
console.log(arr.lastIndexOf(4));
console.log(arr.lastIndexOf(11));

倒序:reverse()
将数组完全颠倒,第一项变成最后一项,最后一项变成第一项。

var arr = [1,2,3,4,5,6,7,8,9,10];
console.log(arr.reverse())

排序:sort(); 默认根据字符编码顺序,从小到大排序
如果想要根据数值大小进行排序,必须添加so改的比较函数参数。
该函数要比较两个值,然后返回一个用于说明这两个值的相对顺序的数字。比较函数应该具有两个参数a和b,根据a和b的关系作为判断条件,返回值根据条件分为三个分支,正数、负数、0:

  • 返回值是负数-1:a排在b前面。
  • 返回值是整数1:a排在b后面。
  • 返回值是0:a和b的顺序保持不变。
    人为能控制的是判断条件。
// 排序,默认按照字符编码顺序从小到大排列
arr.sort();
console.log(arr);
// 添加一个比较函数的参数
arr.sort(function(a,b){
  if (a < b) {
    return -1;   //表示 a 要排在 b 前面
  } else if (a > b) {
    return 1;  //表示 a 要排在 b 后面
  } else {
    return 0;  //表示 a 和 b 保持原样,不换位置
  }
});
console.log(arr);

清空数组的几种方法

arr = [];// 第一种,推荐
arr.length = 0;// 第二种
arr.splice(0, arr.length)// 第三种

基本包装类型

为了方便操作简单数据类型,JavaScript还提供了特殊的简单类型对象:String 基本类型是没有方法的。
当调用str.substring()等方法的时候,先把str包装成String类型的临时对象,再调用substring方法,最后销毁临时对象。

// 基本类型的数据:没有属性和方法
// 对象数据类型:有属性和方法
// 但是字符串是可以调用一些属性和方法
var str = "这是一个字符串";
var str2 = str.slice(3,5);
console.log(str2);
// 基本包装类型:基本类型的数据在进行一些特殊操作时,会暂时被包装成一个对象,结束后再被销毁
// 字符串也有一种根据构造函数创建的方法
var str3 = new String("abcdef");
console.log(str);
console.log(str3);
// 模拟计算机的工作
var str = "这是一个字符串";
// 进行了一个临时的包装
var str4 = new String(str);
var str2 = str4.slice(3,5);
str4 = null;

字符串

字符串是不可变的。
字符串所有的方法,都不会修改字符串本身(字符串是不可变的),操作完成会返回一个新的字符串。
由于字符串的不可变,会占用多余内存,且效率低下,在大量拼接字符串的时候会有效率问题。

字符串属性

长度属性:str.length
字符串长度指的是一个字符串中所有的字符总数。

charAt() 方法可返回指定位置的字符。
char:charator,字符
at:在哪
参数是index字符串的下标。也是从0开始。
表示返回指定的下标位置的字符。

indexOf()方法可返回某个指定的字符串值在字符串中首次出现的位置。
找到指定的子字符串在原字符串中第一次出现的位置的下标。如果子字符串在原字符串中
没有,返回值是-1

concat() 方法用于连接两个或多个字符串。
参数比较灵活,可以是字符串、或者字符串变量、多个字符串。
生成的是一个新的字符串,原字符串不发生变化。

split()
方法用于把不个字符串分割成字符串数组。
参数部分是分割符,利用分割符将字符串分割成多个部分,多个部分作为数组的每一项组成数组。
如果分割符是空字符串,相当于将每个字符拆分成数组中的每一项。

toLowerCase() 把字符串转换为小写
toUpperCase() 把字符串转换为大写
将所有的英文字符转为大写或者小写。
生成的是新的字符串,原字符串不发生变.

slice() 方法可提取字符串的某个部分,并以新的字符串返回被提取的部分。
语法:slice(start,end)
从开始位置截取到结束位置〈不包括结束位置)的字符串。
参数区分正负,正值表示下标位置,负值表示从后面往前数第几个位置,参数可以只传递一个,表示从开始位置截取到字符串结尾。

substr() 方法可在字符串中抽取从start下标开始的指定数目的字符
语法:substr(start,howmany)
从开始位置截取到指定长度的字符串。
start参数区分正负。正值表示下标位置,负值表示从后往前数第几个位置。
howmany参数必须为正数,也可以不写,不写表示从start截取到最后。

substring() 方法用于提取字符串中介于两个指定下标之间的字符。
语法:substring(start,end)
参数只能为正数。
两个参数都是指代下标,两个数字大小不限制,执行方法之前会比较一下两个参数的大小,会用小当做开始位置,大的当做结束位置,从开始位置截取到结束位置但是不包含结束位置。
如果不写第二个参数,从开始截取到字符串结尾。

// 定义一个字符串
var str = "这是一个普通的字符串,abc,   ¥%#";
// 长度属性
console.log(str.length);
//charAt() 返回指定下标位置的字符
console.log(str.charAt(6));
//indexOf() 返回子串在原始字符串中第一次出现位置的下标
console.log(str.indexOf("字符串"));
//concat() 字符串拼接
var str2 = str.concat("哈哈哈","普通");
console.log(str);
console.log(str2);
//split() 分割字符串成一个数组
var arr = str.split(",");
console.log(arr);
//字符串内容倒置
var arr = str.split("");
arr.reverse();
str = arr.join("");
str = str.split("").reverse().join("");
console.log(str);
//大小写转换
var str1 = str.toUpperCase();
var str2 = str1.toLowerCase();
console.log(str);
console.log(str1);
console.log(str2);
//截取字符串方法:三种
slice(start,end) 从开始位置截取到结束位置,但是不包含结束位置
var str1 = str.slice(3,7);
var str1 = str.slice(-7,-3);
var str1 = str.slice(-7);
console.log(str1);
//substr(start,howmany) 从开始位置截取一定长度
var str2 = str.substr(3,7);
var str2 = str.substr(-9,7);
var str2 = str.substr(-9);
console.log(str2);
//substring(start,end) 参数必须是整数,比较两个数的大小,小的作为开始,大的作为结束
var str3 = str.substring(3,7);
var str3 = str.substring(7,3);
var str3 = str.substring(7);
console.log(str3);