【04】 JavaScript基础-pink老师-2022/03

配合食用:
JavaScript基础语法-dom-bom-js-es6新语法-jQuery-数据可视化echarts黑马pink老师前端入门基础

前提须知:

  1. 这里内容主要为: JavaScript基础从变量的定义与使用、流程控制语句、数组、函数、构造函数、内置对象以及对象等.
  2. 由于.我不是计算机专业出身的,但也是学了c语言\python\java的基础课程,所以对于基本的 数据类型\运算符优先级\程序流程之类的基础知识,我这份笔记里是一笔带过的,只针对JavaScript本身特别的点,进行了区别和解释记录.

一、计算机基础知识

编程:计算机为解决某个问题而使用某种程序设计语言编写程序代码,并得到最终结果的过程

计算机程序:计算机所执行的一系列指令集合

计算机语言:人和计算机沟通交流的工具,通过语言来控制操作计算机(机器语言、汇编语言、高级语言)

  • 编程语言:有很强的逻辑性和行为能力的指令,是主动的
  • 标记语言:不向计算机发出指令,常用于格式化和链接。用于被读取,是被动的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DgQMLJUi-1647671642617)(C:\Users\lab-626\AppData\Roaming\Typora\typora-user-images\image-20220226195053942.png)]

数据存储单位: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,undefinednull + Symbol, BigInt

2. 引用类型:复杂数据类型,存储变量中存储的仅仅是地址(引用),因此叫做引用数据类型
通过 new 关键字创建的实例对象(系统对象、自定义对象),如 Object、Array、Function、Date等

2. 堆和栈(stack)

堆栈空间分配区别:

  1. 栈(操作系统):由操作系统自动分配和释放 存放函数的参数值、局部变量的值等。其操作方式类似于数据结构中的栈;
  2. 简单数据类型存放到栈里面,引用类型变量(栈空间)里存放的是地址,真正的对象实例存放在堆空间中
  3. 堆(操作系统):存储复杂类型(对象),一般由程序员分配释放,若程序员不释放,由垃圾回收机制回收。
  4. 复杂数据类型存放到堆里面

参数传递

  1. 简单类型传参:函数的形参也可以看做是一个变量,当我们把一个值类型变量作为参数传给函数的形参时,其实是把变量在栈空间里的值复制了一份给形参,那么在方法内部对形参做任何修改,都不会影响到的外部变量 (特别容易考你输出)。这也是为什么设定了形参, 但未传递实参,在函数内打印该形参,不会报错,而是undefined

  2. 复杂类型传参:函数的形参也可以看做是一个变量,当我们把引用类型变量传给形参时,其实是把变量在栈空间里保存的堆地址复制给了形参,形参和实参其实保存的是同一个堆地址,所以操作的是同一个对象。
    注意: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

面试常考的数组手撕算法

  1. 数组去重, 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)]
}
  1. 数组扁平化, 一个用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));
  1. 排序算法
4. 冒泡排序法【两两交换】
	1. 单次排序中,2个相邻元素比较大小,交换位置,最后1个元素一定是最值
	2. 所有元素排列完,需要length-1for (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-12. 将最值与首元素交换位置,交换2个数,需要1个临时变量temp
	3. 最终一共需要重复上面的步骤length-1var 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. 预解析:将 varfunction 声明的变量提到 当前作用域 的最前面,即在内存中进行提前声明或者定义
	+ 变量预解析(变量提升):变量声明会被提升到当前作用域的最上面,变量的赋值不会提升!!!
	+ 函数预解析(函数提升):函数声明会被提升到当前作用域的最上面,但是不会调用函数!!!
	+ 只提升varfunction的声明, 不提升其初始化或调用, 函数提升的优先级高于变量提升(会考同名覆盖问题)
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 中,对象是一组无序的相关属性和方法的集合,所有的事物都是对象,例如字符串、数值、数组、函数等。
对象是由属性和方法组成的,都不需要声明。
属性:事物的特征,在对象中用属性来表示,不需要声明(常用名词)
方法:事物的行为和功能,在对象中用方法来表示,不需要声明(常用动词)

  1. 创建对象的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);

  1. 对象的调用

    • 对象里面的属性调用 : 对象.属性名 ,这个小点 . 可以理解为 “的”

    • 对象里面属性的另一种调用方式 : 对象[‘属性名’],注意方括号里面的属性必须加引号

    • 对象里面的方法调用:对象.方法名() ,注意这个方法名字后面一定加括号

  2. new 在执行时会做四件事情

    1. 在内存中分配一块空间给新对象
    2. this指向新对象
    3. 执行构造函数代码,给新对象添加属性和方法
    4. 返回 这个新对象
    function _new(fn, ...args) {
        const obj = Object.create(fn.prototype)
        const newObj = fn.apply(obj, args)
        return newObj instanceof Object ? newObj : obj;
    }
    
  3. 遍历对象的属性

    其语法如下:
    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 对象是基于197011日(世界标准时间)起的毫秒数

 + Date 对象和 Math 对象不一样,它是一个构造函数,需要实例化后才能使用
 + Date 实例用来处理日期和时间
 + 获取日期的总的毫秒形式【4种】:返回自 19701100: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()转换小写

常考: 千分符, 驼峰命名法和下划线命名法的相互转化

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值