配合食用:
JavaScript基础语法-dom-bom-js-es6新语法-jQuery-数据可视化echarts黑马pink老师前端入门基础
前提须知:
- 这里内容主要为: JavaScript基础从变量的定义与使用、流程控制语句、数组、函数、构造函数、内置对象以及对象等.
- 由于.我不是计算机专业出身的,但也是学了c语言\python\java的基础课程,所以对于基本的 数据类型\运算符优先级\程序流程之类的基础知识,我这份笔记里是一笔带过的,只针对JavaScript本身特别的点,进行了区别和解释记录.
一、计算机基础知识
编程:计算机为解决某个问题而使用某种程序设计语言编写程序代码,并得到最终结果的过程
计算机程序:计算机所执行的一系列指令集合
计算机语言:人和计算机沟通交流的工具,通过语言来控制操作计算机(机器语言、汇编语言、高级语言)
- 编程语言:有很强的逻辑性和行为能力的指令,是主动的
- 标记语言:不向计算机发出指令,常用于格式化和链接。用于被读取,是被动的。
数据存储单位:bit(最小存储单位)、byte(8bit)、KB(1024)、MB、GB、TB
程序运行:先将程序代码从 硬盘(慢性子) - 加载到 内存条 - 再通过cpu(急性子)执行
二、JS基础知识
定义:运行在客户端的脚本语言,脚本语言不需要编译,运行过程由js解释器(js引擎)逐行解释并执行,既可以做前端也可以做后端
JS特点:
1. 解释型语言(不用编译,直接运行)
2. 类似有c和java的语法结构
3. 动态语言
4. 基于原型的面向对象
JS作用:
+ 表单动态校验(密码强度检测)
+ 网页特效
+ 服务端开发(Node.js)
+ 桌面程序(Electron)
+ App(Cordova)
+ 控制硬件-物联网(Ruff)
+ 游戏开发(cocos2d-js)
浏览器执行JS:
浏览器分成两个部分:
+ 渲染引擎:用来解析html和css,俗称内核,比如chrome浏览器的blink,老版本的webkit
+ JS引擎(JS解释器):用来读取网页中的JS代码,对其运行后处理,比如chrome的V8
JS组成:
+ ECMAScript(JS语法,厂商共同遵循的工业协议)
+ DOM(页面文档对象模型)
+ BOM (浏览器对象模型)
JS三种书写位置:行内、内嵌和外部(和css一样)
JS输入输出语句:
+ alert 弹出警示框
+ prompt 弹出输入框
+ console 控制台输出 程序员测试使用
三、JS变量
变量:程序在内存中申请用来存放数据的一块空间
声明变量:var 变量名; //通过变量名访问内存申请的空间,驼峰命名法
初始化变量:声明并赋值
同时声明多个变量用逗号,隔开
JS是一种弱类型或者说动态语言,在程序运行中类型会被自动确定,不用提前声明。变量的数据类型是JS引擎根据 右边变量值的数据类型判断的。
1. 简单类型与复杂类型
- 简单数据类型(Number、String、Boolean、Undefined、Null 新增 Symbol bigInt)
- 复杂数据类型(Object Array Function)
- JS数字类型,八进制在前面+0,十六进制在前面+0x,三个特殊值:Infinity、-Infinity、NaN非数值
数据类型检测方案
- typeof var 对于基本数据类型皆可检测正确, 复杂数据类型都是Object, 无法区分函数, 数组和对象
- 对象实例 instanceof 构造函数 用于检测构造函数的prototype是否在对象实例的原型链(面试必考,自行了解)上, 可以准确区分复杂类型, 去了解原型链可以发现, 并不会准确区分, 除非是只溯源一层.
- Object.prototype.toString.call(var) 可以正确检测任何变量的类型
数据类型转换:使用表单、prompt获取数据默认为字符串类型,不能直接进行算数运算,需要先转换
- 转换为数字型:parseInt(string)、parseFloat(string)、Number(string)、利用算数运算隐式转换
- 转换为Bool值:Boolean(), JS中的假值只有5个: 0、NaN、null、undefined、空字符串 都会转换为false,其他都是ture
简单类型 / 基本数据类型 / 值类型 【5个 + 2个 新增】
复杂类型 / 引用类型 [数组/对象/函数]
注意: 简单数据类型 null 返回类型是一个空对象object (当初设计时的bug)
巧思: 如果有一个变量打算之后存储为对象,暂时没想好内容,可以给null
1. 值类型:简单数据类型/基本数据类型,存储变量中存储的是值本身,因此叫做值类型
string ,number,boolean,undefined,null + Symbol, BigInt
2. 引用类型:复杂数据类型,存储变量中存储的仅仅是地址(引用),因此叫做引用数据类型
通过 new 关键字创建的实例对象(系统对象、自定义对象),如 Object、Array、Function、Date等
2. 堆和栈(stack)
堆栈空间分配区别:
- 栈(操作系统):由操作系统自动分配和释放 存放函数的参数值、局部变量的值等。其操作方式类似于数据结构中的栈;
- 简单数据类型存放到栈里面,引用类型变量(栈空间)里存放的是地址,真正的对象实例存放在堆空间中
- 堆(操作系统):存储复杂类型(对象),一般由程序员分配释放,若程序员不释放,由垃圾回收机制回收。
- 复杂数据类型存放到堆里面
参数传递
-
简单类型传参:函数的形参也可以看做是一个变量,当我们把一个值类型变量作为参数传给函数的形参时,其实是把变量在栈空间里的值复制了一份给形参,那么在方法内部对形参做任何修改,都不会影响到的外部变量 (特别容易考你输出)。这也是为什么设定了形参, 但未传递实参,在函数内打印该形参,不会报错,而是undefined
-
复杂类型传参:函数的形参也可以看做是一个变量,当我们把引用类型变量传给形参时,其实是把变量在栈空间里保存的堆地址复制给了形参,形参和实参其实保存的是同一个堆地址,所以操作的是同一个对象。
注意:JavaScript中没有堆栈的概念,通过堆栈的方式,可以让大家更容易理解代码的一些执行方式,便于将来学习其他语言。
3. 运算符(operator)
定义:也被称为操作符,是用于实现赋值、比较和执行算数运算等功能的符号。
常用运算符:
- 算数运算符:不要直接判断2个浮点数是否相等(0.07*100=7.00000000000001)
- 递增、递减运算符:既可以放在变量前面(前置,先加),也可以放在变量后面(后置,先返回再加)
- 比较运算符:=== 全等(要求值和数据类型都一致), == 默认转换数据类型(18==‘18’ true)
- [这是一个很大的知识点, 隐式转换 == + - 需要自己去了解, 必考]
逻辑运算符:
- 短路运算(逻辑中断)的原理: 当有多个表达式(值)时,左边的表达式值可以确定结果时,就不再继续运算右边的表达式的值;
赋值运算符
4. 运算符优先级
很没办法了解招聘者能力的公司, 考题面试的时候会考这个, 比如 i++, ++i, i+++++i
四、JS流程控制
流程控制就是来控制我们的代码按照什么结构顺序来执行,主要有三种结构,分别是
- 顺序结构
- 分支结构:if switch;三元表达式(表达式1?表达式:表达式;)
- 循环结构:for while do…while
断点调试:
自己在程序的某一行设置一个断点,调试时程序运行到这一步就会停下,
然后自己可以一步一步调试,可以看到各个变量当前值。
调试到有bug的地方会显示错误停止运行。这有助于我们观察程序的运行过程
断点调试步骤:
1. 浏览器按F12 -》 source -》 找到需要调试文件 -》 在程序观察处设置断点 -》 刷新
2. watch:添加需要监视的变量,通过watch可以监视变量值变化
3. F11:程序单步执行,观察watch中变量值变化
JavaScript 命名规范
1. 标识符命名规范
+ 变量、函数的命名必须有意义(驼峰命名法)
+ 变量的名称一般用 名词
+ 函数的名称一般用 动词
2. 操作符规范
+ 操作符的左右两侧各保留一个空格
五、JS数组
数组(Array):一组数据的集合,其中每个数据被称作元素,在数组中可以存放任意类型的元素, 是一种将一组数据存储在单个变量名下的优雅方式
创建方式
- 利用new创建数组: var 数组名 = new Array();
- 利用数组字面量创建数组: var 数组名 = [1,‘小白’, true, 4];
数组可以通过 数组名[索引/下标] 来访问、设置、修改对应的数组元素
使用 数组名.length 可以访问数组元素长度
可以通过修改length的值新增数组元素,length属性是可读写的,未声明变量值默认为undefined,可以通过指定数组索引的方式追加数组元素
var arr = ['red', 'green', 'blue', 'pink'];
arr[7] = 'hotpink';
console.log(arr); //[ 'red', 'green', 'blue', 'pink', <3 empty items>, 'hotpink' ]
检测是否为数组:
instanceof 运算符,可以判断一个对象是否属于某种类型
Array.isArray() 用于判断一个对象 是否是 数组
var arr = [1, 23];
var obj = {};
console.log(arr instanceof Array); // true
console.log(arr instanceof Object); // true instanceof的定义: 找后者的prototype是否在前者原型链上
console.log(obj instanceof Array); // false
console.log(Array.isArray(arr)); // true
console.log(Array.isArray(obj)); // false
方法名 | 说明 | 返回值 |
---|---|---|
添加/删除数组元素的方法 | ||
push(参数1…) | 尾部添加1个或多个元素,修改原数组 | 返回新长度 |
pop() | 删除数组尾元素,数组长度-1 | 返回删除值 |
unshift(参数1…) | 首部添加1个或多个元素 | 返回新长度 |
shift() | 删除数组首元素,数组长度-1 | 返回删除值 |
数组排序方法 | ||
reverse() | 颠倒数组顺序 | 改变原数组 返回新数组 |
sort(function(a,b) {return a-b}) | 对数组元素排序 | 改变原数组 返回新数组 |
数组索引方法 | ||
indexOf() | 查找指定元素的第一个索引 | 存在返回索引值,不存在-1 |
lastIndexOf() | 数组最后一个的索引 | 存在返回索引值,不存在-1 |
includes(valueToFind) | 判断一个数组是否包含一个指定的值 | 根据是否存在返回布尔值 |
数组转换为字符串 | ||
toString() | 把数组转换成 逗号分隔 的1个字符串 | 返回1个字符串 |
join(‘分隔符’) | 把数组转换成 分隔符分隔 的1个字符串 | 返回1个字符串 |
其他重要方法 | ||
concat() | 连接2或多个数组,不影响原数组 | 返回1个新数组 |
slice(begin, end) | 数组截取,不影响原数组 | 返回被截取的新数组 |
splice(begin, deleteCount, [item1, item2, …]) | 数组删除/替换,影响原数组 | 被删除元素组成的新数组/空数组 |
filter | 创建一个新数组,包含通过测试函数的所有元素 | 返回1个新数组 |
flat | 数组扁平化和移除空项,可指定深度Infinity | 返回1个新数组 |
forEach(callback(currentValue [, index [, array]])) | 遍历数组, 去除空值 | 返回值undefined |
面试常考的数组手撕算法
- 数组去重, ES6之后用Set对象, 一步到位, 会的方法越多越好, 但严格来说就分两类
//查询 原数组元素 是否在 新数组 中存在,不存在返回值-1,则将该元素放入新数组
function delRepeat(arr) {
var newArr = new Array()
for (var i=0; i<arr.length; i++) {
//if (!newArr.includes(arr[i])){
if (newArr.indexOf(arr[i]) == -1) {
newArr.push(arr[i])
}
}
console.log(newArr)
}
//利用ES6新特性 Set对象
function delRepeat(arr){
return [...new Set(arr)]
}
- 数组扁平化, 一个用flat, 一个用递归, 区别在于是否去除空值
var arr = [1, , 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]];
console.log(arr.flat(Infinity)); //空值会报被去掉
function flatArr(arr, newArr = []) { //空值不会被去掉
for (let i = 0; i < arr.length; i++) {
if (Array.isArray(arr[i])) {
flatArr(arr[i], newArr)
} else {
newArr.push(arr[i])
}
}
return newArr
}
console.log(flatArr(arr));
4. 冒泡排序法【两两交换】
1. 单次排序中,2个相邻元素比较大小,交换位置,最后1个元素一定是最值
2. 所有元素排列完,需要length-1次
for (var i=0; i<arr1.length-1; i++) {
for (var j=0; j<arr1.length-i-1; j++) {
if (arr1[j] > arr1[j+1]) {
temp = arr1[j];
arr1[j] = arr1[j+1];
arr1[j+1] = temp;
}
}
}
2. 选择排序法【最值】
1. 找出当前数组中的最值,需要1个变量min记录最值下标,需要比较length-1次
2. 将最值与首元素交换位置,交换2个数,需要1个临时变量temp
3. 最终一共需要重复上面的步骤length-1次
var temp, min;
for (var i=0; i<arr1.length-1; i++) {
min = i;
for (var j=i+1; j<arr1.length; j++) {
if (arr1[min] > arr1[j]) {
min = j;
}
}
if (i != min) { //这个判断加上好一些,如果最小值相同就不用交换了
temp = arr1[min];
arr1[min] = arr1[i];
arr1[i] = temp;
}
}
3. 插入排序
var arr = [2, 0, 6, 1, 77, 0, 52, 25, 7, 99,88,2];
var arrY = [];
arrY[0] = arr[0];
for (var i=0; i<arr.length-1; i++) {
for (var j=arrY.length; j>0; j--) {
if ((arr[i+1] < arrY[j-1])) {
arrY[j] = arrY[j-1];
}
else {
arrY[j] = arr[i+1];
break;
}
arrY[j-1] = arr[i+1];
}
}
4. 快速排序
function quickSort(arr) {
if (arr.length <= 1) {
return arr
}
let pivotIndex = Math.floor(arr.length / 2)
console.log(pivotIndex);
// let pivot = arr.splice(pivotIndex, 1) //返回被删除/替换的新数组
let pivot = arr.splice(pivotIndex, 1)[0] //得到基准元素
console.log(pivot);
let left = []
let right = []
arr.forEach(v => {
if (v > pivot) {
right.push(v)
} else {
left.push(v)
}
})
return quickSort(left).concat([pivot], quickSort(right))
}
六 、JS函数
函数:就是封装了一段可被重复调用执行的代码块。通过此代码块可以实现大量代码的重复使用。
函数在使用时分为两步:声明函数和调用函数。
function 函数名() { // 声明函数
//函数体代码
}
函数名(); // 通过调用函数名来执行函数体代码
由于函数一般是为了实现某个功能才定义的, 所以通常我们将函数名命名为动词,比如 getSum
实参和形参的多个参数之间用逗号(,)分隔,在JavaScript中,形参的默认值是undefined
return 只能返回一个值。如果用逗号隔开多个值,以最后一个为准
当我们不确定有多少个参数传递的时候,可以用 arguments 来获取。在 JavaScript 中,
arguments 实际上它是当前函数的一个内置对象。所有函数都内置了一个 arguments 对象,
arguments 对象中存储了传递的所有实参。
相当于 实参 伪数组,按索引方式存储数据,具有length属性,但不具有数组的pop和push等方法
函数的两种声明方式
1. 命名函数(function),可以先调用后声明, 因为用function声明的函数会被提升到作用域的最顶端
function 函数名 (形参) {函数体}
2. 匿名函数,函数调用的代码必须写到函数体后面
var 函数名= function (形参) {函数体}
七、JS 作用域
概述:通常来说,一段程序代码中所用到的名字并不总是有效 和 可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。简而言之, **作用域规定了变量的访问方式, 或变量的生命周期。**作用域的使用提高了程序逻辑的局部性,增强了程序的可靠性,减少了名字冲突。
JavaScript(es6前)中的作用域有两种:
全局作用域:作用于所有代码执行的环境(整个 script 标签内部)或者一个独立的 js 文件。
局部作用域(函数作用域):作用于函数内的代码环境,就是局部作用域。 因为跟函数有关系,所以也称为函数作用域。
块级作用域(es6):块作用域由 { },关键字 let
全局变量:在任何一个地方都可以使用,只有在浏览器关闭时才会被销毁,因此比较占内存
局部变量:只在函数内部使用,当其所在的代码块被执行时,会被初始化;当代码块运行结束后,就会被销毁,因此更节省内存空间
八、JS 预解析
JS 代码是由浏览器中的 JS 解析器来执行的,运行时分2步:
1. 预解析:将 var 和 function 声明的变量提到 当前作用域 的最前面,即在内存中进行提前声明或者定义
+ 变量预解析(变量提升):变量声明会被提升到当前作用域的最上面,变量的赋值不会提升!!!
+ 函数预解析(函数提升):函数声明会被提升到当前作用域的最上面,但是不会调用函数!!!
+ 只提升var和function的声明, 不提升其初始化或调用, 函数提升的优先级高于变量提升(会考同名覆盖问题)
2. 代码执行: 从上到下执行JS语句
//坑1
console.log(num);
var num = 10; // undefined
预解析之后相当于
var num;
console.log(num);
num = 10;
坑2
fn(); //匿名函数不会被提升, TypeError: fn is not a function
var fn = function() {
console.log('想不到吧');
}
预解析后相当于
var fn;
fn();
fn = function() {
console.log('想不到吧');
}
坑3
alert(a); //function a(){ return false; }
var a = 1;
alert(a);//1 函数和变量同名提升, 未赋值时, 函数覆盖变量, 变量赋值后函数被覆盖
function a(){
return false;
}
预解析后相当于
var a;
function a(){
return false;
}
alert(a);
a = 1;
alert(a);
坑4
f1();
console.log(c) //9
console.log(b) //9
console.log(a) //报错
function f1 () {
var a=b=c=9; //相当于 var a=9; b=9; c=9; 直接赋值,没有var 声明,当做全局变量看待(区别 var a=9,b=9,c=9;)
console.log(c) //9
console.log(b) //9
console.log(a) //9
}
九、JS 对象
在 JavaScript 中,对象是一组无序的相关属性和方法的集合,所有的事物都是对象,例如字符串、数值、数组、函数等。
对象是由属性和方法组成的,都不需要声明。
属性:事物的特征,在对象中用属性来表示,不需要声明(常用名词)
方法:事物的行为和功能,在对象中用方法来表示,不需要声明(常用动词)
- 创建对象的3种方式:
1. 利用字面量创建对象
对象字面量: var 对象名 = {用逗号隔开的键值对}, {}包含了这个具体事物(对象)的属性和方法
2. 利用 new Object 创建对象 【对象实例化】
var 对象名 = new Object() 对象名.属性名=值 对象名.方法名=function () {函数体}
3. 利用构造函数创建对象
构造函数 :是一种特殊的函数,主要用来初始化对象,即为对象成员变量赋初始值,它总与 new 运算符一起使用。
抽象了对象的公共部分,封装到了函数里面,它泛指某一大类(class),不需要return
在 js 中,使用构造函数要时要注意以下 2 点:
1. 构造函数用于创建某一类对象,其首字母大写【这是约定!!!】
2. 构造函数要和 new 一起使用才有意义, 因为构造函数也是函数, 可以直接调用, 但实际上它诞生的使命在于创建对象
function Person(name, age, sex) {
this.name = name; 【this 指向实例化对象】
this.age = age;
this.sex = sex;
this.sayHi = function() {
alert('我的名字叫:' + this.name + ',年龄:' + this.age + ',性别:' + this.sex);
}
}
var bigbai = new Person('大白', 100, '男');
var smallbai = new Person('小白', 21, '男');
console.log(bigbai.name);
console.log(smallbai.name);
-
对象的调用:
-
对象里面的属性调用 : 对象.属性名 ,这个小点 . 可以理解为 “的”
-
对象里面属性的另一种调用方式 : 对象[‘属性名’],注意方括号里面的属性必须加引号
-
对象里面的方法调用:对象.方法名() ,注意这个方法名字后面一定加括号
-
-
new 在执行时会做四件事情:
- 在内存中分配一块空间给新对象
- this指向新对象
- 执行构造函数代码,给新对象添加属性和方法
- 返回 这个新对象
function _new(fn, ...args) { const obj = Object.create(fn.prototype) const newObj = fn.apply(obj, args) return newObj instanceof Object ? newObj : obj; }
-
遍历对象的属性
其语法如下: for...in 语句用于对数组或者对象的属性进行循环操作 for (变量 in 对象名字) { // 在此执行代码 } 语法中的变量是自定义的,它需要符合命名规范,通常我们会将这个变量写为 k 或者 key。 for (var k in obj) { console.log(k); // 这里的 k 是属性名 console.log(obj[k]); // 这里的 obj[k] 是属性值 }
十、JS内置对象(Math、 Date 、Array、String)
-
JavaScript 中的对象分为3种:自定义对象 、内置对象、 浏览器对象(JS独有);前面两种对象是JS 基础内容,属于 ECMAScript; 第三个浏览器对象属于我们JS独有的, 我们JS API 讲解
-
内置对象: JS 语言自带的一些对象,这些对象供开发者使用,并提供了一些常用的或是最基本而必要的功能(属性和方法)
-
最大的优点:帮助我们快速开发
-
JavaScript 提供了多个内置对象:Math、 Date 、Array、String等(查文档MDN
1. Math对象
不是构造函数,它具有数学常数和函数的属性和方法。数学相关的运算(求绝对值,取整、最大值等)可使用 Math 中的成员
Math.random() 方法可以随机返回一个小数,其取值范围是 [0,1),左闭右开 0 <= x < 1
2. Date对象
Date 对象是基于1970年1月1日(世界标准时间)起的毫秒数
+ Date 对象和 Math 对象不一样,它是一个构造函数,需要实例化后才能使用
+ Date 实例用来处理日期和时间
+ 获取日期的总的毫秒形式【4种】:返回自 1970 年 1 月 1 日 00:00:00 (UTC) 到当前时间的毫秒数
// 实例化Date对象
var now = new Date();
// 1. 用于获取对象的原始值
console.log(date.valueOf())
console.log(date.getTime())
// 2. 简单写可以这么做
var now = + new Date();
// 3. HTML5中提供的方法,有兼容性问题
var now = Date.now();
//日期格式化 2022年12月1日 星期二 11:21:22
function getTime() {
var now = new Date();
week = ['日','一','二','三','四','五','六']
year = now.getFullYear()
month = now.getHours()
date = now.getDate()
day = now.getDay()
h = now.getHours()
h = h<10 ? '0'+h : h;
m = now.getMinutes()
m = m<10 ? '0'+m : m;
s = now.getSeconds()
s = s<10 ? '0'+s : s;
console.log(year + '年' + (month+1) + '月' + date + '日' + ' 星期' + week[day])
console.log(h + ':' + m + ':' + s)
}
案例:倒计时效果
核心算法:输入的时间减去现在的时间就是剩余的时间,即倒计时,但是不能拿着时分秒相减,比如 05 分减去25分,结果会是负数的。用时间戳来做。
1. 用户输入时间总的毫秒数减去现在时间的总的毫秒数,得到的就是剩余时间的毫秒数
2. 把剩余时间总的毫秒数转换为天、时、分、秒 (时间戳转换为时分秒)
转换公式如下:
d = parseInt(总秒数/ 60/60 /24); // 计算天数
h = parseInt(总秒数/ 60/60 %24) // 计算小时
m = parseInt(总秒数 /60 %60 ); // 计算分数
s = parseInt(总秒数%60); // 计算当前秒数
function countDwon(time) {
var nowTime = +new Date();
var userTime = +new Date(time);
var span = userTime - nowTime;
totalSec = parseInt(span/1000);
s = parseInt(totalSec %60);
m = parseInt(totalSec/60 %60);
h = parseInt(totalSec/60/60 %24);
day = parseInt(totalSec/60/60 /24);
h = h<10 ? '0'+h : h;
m = m<10 ? '0'+m : m;
s = s<10 ? '0'+s : s;
console.log('剩余时间:' + day + '天' + h + '小时' + m + '分' + s + '秒')
}
countDwon('2022-3-2') //剩余时间:0天08小时56分34秒
3. 字符串对象
- 基本包装类型
为了方便操作基本数据类型,JavaScript 还提供了三个特殊的引用类型:String、Number和 Boolean。
基本包装类型就是把简单数据类型包装成为复杂数据类型,这样基本数据类型就有了属性和方法。
下面代码 没有问题, 本身基本数据类型是不具有属性和方法的,但js会将基本数据类型包装为复杂数据类型(对象)
var str = 'andy';
console.log(str.length);
其执行过程如下 :
// 1. 生成临时变量,把简单类型包装为复杂数据类型
var temp = new String('andy');
// 2. 赋值给我们声明的字符变量
str = temp;
// 3. 销毁临时变量
temp = null;
字符串的不可变:指的是里面的值不可变,虽然看上去可以改变内容,但其实是地址变了,内存中新开辟了一个内存空间。
字符串所有的方法,都不会修改字符串本身(字符串是不可变的),操作完成会返回一个新的字符串
var str = 'abc';
str = 'hello';
// 当重新给 str 赋值的时候,常量'abc'不会被修改,依然在内存中
// 重新给字符串赋值,会重新在内存中开辟空间,这个特点就是字符串的不可变
// 由于字符串的不可变,在大量拼接字符串的时候会有效率问题
var str = '';
for (var i = 0; i < 100000; i++) {
str += i;
}
console.log(str); // 这个结果需要花费大量时间来显示,因为需要不断的开辟新的空间
案例:
1. 查找字符串"abcoefoxyozzopp"中所有o出现的位置以及次数(indexOf(指定字符 ,起始位置))
var str = "abcoefoxyozzopp";
var times = 0;
var position = new Array();
var index = 0;
while (str.indexOf('o', index) != -1) {
index = str.indexOf('o', index);
position.push(index);
times++;
index++;
}
判断一个字符串 'abcoefoxyozzopp' 中出现次数最多的字符,并统计其次数(形成 字符:出现次数 键值对 存储到对象中)
var str = 'abcoefoxyozzopp'
var charDict = new Object()
for (var i = 1; i < str.length; i++) {
if (charDict[str[i]]) {
charDict[str[i]]++;
} else {
charDict[str[i]] = 1; //不能写成 charDict.str[i] = 1; 等价于 charDict.'x' = 1; 报错
}
}
var times = 0; //遍历输出
for (k in charDict) {
if (charDict[k] > times) {
times = charDict[k];
char = k;
}
}
根据位置返回字符(重点)
方法 | 说明 | 返回值 |
---|---|---|
根据字符返回索引 | ||
indexOf(‘要查找的字符’, 开始的位置) 【用于查找某元素出现位置及次数】 | 返回指定字符在元字符串位置 | 找不到返回-1 |
lastIndexOf() | 从后往前找,只找第1个匹配的 | |
根据索引返回字符 | ||
charAt(index) | 指定位置字符 | |
charCodeAt(index) | 指定位置字符的ASCII码 | |
str[index] | 获取指定位置字符 | |
字符串操作方法 | ||
concat(str1, str2, str3) | 拼接多个字符串 | 等价于+ |
slice(start, end) | 切片,左闭右开 | |
substring(start, end) | 如上,但不接受负值 | |
replace(regexp/substr, newSubStr/function) | dst替换src字符串 | |
split(‘分隔符’) | 根据分隔符切分字符串 | 数组 |
toUpperCase() | 转换大写 | |
toLowerCase() | 转换小写 |
常考: 千分符, 驼峰命名法和下划线命名法的相互转化