JavaScript 是世界上最流行的语言之一,是一种运行在客户端的脚本语言 (Script 是脚本的意思)
JavaScript的作用
浏览器分成两部分:渲染引擎和 JS 引擎
浏览器本身并不会执行JS代码,而是通过内置 JavaScript 引擎(解释器) 来执行 JS 代码 。JS 引擎执行代码时逐行解释每一句源码(转换为机器语言),然后由计算机去执行,所以 JavaScript 语言归为脚本语言,会逐行解释执行。
JavaScript由ECMAScript(JavaScript语法)、DOM(页面文档对象模型)、BOM(浏览器对象模型)组成。
ECMAScript 是由ECMA 国际( 原欧洲计算机制造商协会)进行标准化的一门编程语言,这种语言在万维网上应用广泛,它往往被称为 JavaScript或 JScript,但实际上后两者是 ECMAScript 语言的实现和扩展。
ECMAScript:规定了JS的编程语法和基础核心知识,是所有浏览器厂商共同遵守的一套JS语法工业标准。
文档对象模型(DocumentObject Model,简称DOM),是W3C组织推荐的处理可扩展标记语言的标准编程接口。通过 DOM 提供的接口可以对页面上的各种元素进行操作(大小、位置、颜色等)
浏览器对象模型(Browser Object Model,简称BOM) 是指浏览器对象模型,它提供了独立于内容的、可以与浏览器窗口进行互动的对象结构。通过BOM可以操作浏览器窗口,比如弹出框、控制浏览器跳转、获取分辨率等。
JS 有3种书写位置,分别为行内、内嵌和外部。
1、行内式 JS
<input type="button" value="点我试试" onclick="alert('Hello World')" />
2、内嵌 JS
3、外部 JS
JS中的注释主要有两种,分别是单行注释和多行注释。
单行注释( 快捷键 cmd + / )的注释方式如下:
// 我是注释
多行注释( 默认快捷键 alt + shift + a )的注释方式如下:
/*
我是
多行
注释
*/
JS中提供了一些输入输出语句,其常用的语句如下:
变量是程序在内存中申请的一块用来存放数据的空间。
// 声明变量
var age; // 声明一个 名称为age 的变量
age = 10; // 给 age 这个变量赋值为 10
声明一个变量并赋值,称之为变量的初始化。
var age = 18; // 声明变量同时赋值为 18
一个变量被重新复赋值后,它原有的值就会被覆盖,变量值将以最后一次赋的值为准。
var age = 18;
age = 81; // 最后的结果就是81因为18 被覆盖掉了
同时声明多个变量时,只需要写一个 var, 多个变量名之间使用英文逗号隔开。
var age = 10, name = 'zs', sex = 2;
声明变量特殊情况
情况 | 说明 | 结果 |
---|---|---|
var age ; console.log (age); | 只声明 不赋值 | undefined |
console.log(age) | 不声明 不赋值 直接使用 | 报错 |
age = 10; console.log (age); | 不声明 只赋值 | 10 |
变量命名规范:
在计算机中,不同的数据所需占用的存储空间是不同的,为了便于把数据分成所需内存大小不同的数据,充分利 用存储空间,于是定义了不同的数据类型。
JavaScript 是一种弱类型或者说动态语言。这意味着不用提前声明变量的类型,在程序运行过程中,类型会被自动确定:
var age = 10; // 这是一个数字型
var areYouOk = '是的'; // 这是一个字符串
在代码运行时,变量的数据类型是由 JS引擎 根据 = 右边变量值的数据类型来判断 的,运行完毕之后, 变量就确定了数据类型。JavaScript 拥有动态类型,同时也意味着相同的变量可用作不同的类型:
var x = 6; // x 为数字
var x = "Bill"; // x 为字符串
JS 把数据类型分为两类:
JavaScript 数字类型既可以保存整数,也可以保存小数(浮点数)。
var age = 21; // 整数
var Age = 21.3747; // 小数
最常见的进制有二进制、八进制、十进制、十六进制。
// 1.八进制数字序列范围:0~7
var num1 = 07; // 对应十进制的7
var num2 = 019; // 对应十进制的19
var num3 = 08; // 对应十进制的8
// 2.十六进制数字序列范围:0~9以及A~F
var num = 0xA;
JavaScript中数值的最大和最小值
数字型三个特殊值
isNaN():用来判断一个变量是否为非数字的类型,返回 true 或者 false
var usrAge = 21;
var isOk = isNaN(userAge);
console.log(isNum); // false ,21 不是一个非数字
var usrName = "andy";
console.log(isNaN(userName));// true ,"andy"是一个非数字
字符串型可以是引号中的任意文本,其语法为 双引号 “” 和 单引号’’
var strMsg = "我爱北京天安门~"; // 使用双引号表示字符串
var strMsg2 = '我爱吃猪蹄~'; // 使用单引号表示字符串
// 常见错误
var strMsg3 = 我爱大肘子; // 报错,没使用引号,会被认为是js代码,但js没有这些语法
因为 HTML 标签里面的属性使用的是双引号,JS 这里我们更推荐使用单引号。
JS 可以用单引号嵌套双引号 ,或者用双引号嵌套单引号 (外双内单,外单内双)
var strMsg = '我是"高帅富"程序猿'; // 可以用''包含""
var strMsg2 = "我是'高帅富'程序猿"; // 也可以用"" 包含''
// 常见错误
var badQuotes = 'What on earth?"; // 报错,不能 单双引号搭配
类似HTML里面的特殊字符,字符串中也有特殊字符,称之为转义符。转义符都是 \ 开头的,常用的转义符及其说明如下:
转义符 | 解释说明 |
---|---|
\ n | 换行符,n 是 newline 的意思 |
\ \ | 斜杠 \ |
\ ’ | ’ 单引号 |
\ " | ”双引号 |
\ t | tab 缩进 |
\ b | 空格 ,b 是 blank 的意思 |
字符串是由若干字符组成的,这些字符的数量就是字符串的长度。通过字符串的 length 属性可以获取整个字符串的长度。
var strMsg = "我是帅气多金的程序猿!";
alert(strMsg.length); // 显示 11
多个字符串之间可以使用 + 进行拼接,其拼接方式为 字符串 + 任何类型 = 拼接之后的新字符串
拼接前会把与字符串相加的任何类型转成字符串,再拼接成一个新的字符串
//1.1 字符串 "相加"
alert('hello' + ' ' + 'world'); // hello world
//1.2 数值字符串 "相加"
alert('100' + '100'); // 100100
//1.3 数值字符串 + 数值
alert('11' + 12); // 1112
布尔类型有两个值:true 和 false ,其中 true 表示真(对),而 false 表示假(错)。
布尔型和数字型相加的时候, true 的值为 1 ,false 的值为 0。
console.log(true + 1); // 2
console.log(false + 1); // 1
一个声明后没有被赋值的变量会有一个默认值undefined ( 如果进行相连或者相加时,注意结果)
var variable;
console.log(variable); // undefined
console.log('你好' + variable); // 你好undefined
console.log(11 + variable); // NaN
console.log(true + variable); // NaN
一个声明变量给 null 值,里面存的值为空
var vari = null;
console.log('你好' + vari); // 你好null
console.log(11 + vari); // 11
console.log(true + vari); // 1
typeof 可用来获取检测变量的数据类型
var num = 18;
console.log(typeof num) // 结果 number
不同类型的返回值:
类型 | 示例 | 结果 |
---|---|---|
number | typeof 1 | “number” |
string | typeof ‘xx’ | “string” |
boolean | typeof true | “boolean” |
undefined | typeof undefined | “undefined” |
null | typeof null | “object” |
使用表单、prompt 获取过来的数据默认是字符串类型的,此时就不能直接简单的进行加法运算,而需要转换变量的数据类型。
1、转换为字符串
2、转换为数字型(重点)
parseInt(string)函数,将字符串转换为整数数字型
parseFloat(string)函数,将字符串转换为浮点数数字型
Nuber(string)函数,将字符串强制转换为数字型
js隐式转换(- * /),利用算术运算隐式转换为数字型
3、转换为布尔型
Boolean()函数,将其他类型转换为数字型
console.log(Boolean('')); // false
console.log(Boolean(0)); // false
console.log(Boolean(NaN)); // false
console.log(Boolean(null)); // false
console.log(Boolean(undefined)); // false
console.log(Boolean('小白')); // true
console.log(Boolean(12)); // true
计算机不能直接理解任何除机器语言以外的语言,所以必须要把程序员所写的程序语言翻译成机器语言才能执行程序。程序语言翻译成机器语言的工具,被称为翻译器。
翻译器翻译的方式有两种:一个是编译,另外一个是解释。两种方式之间的区别在于翻译的时间点不同
标识(zhi)符:就是指开发人员为变量、属性、函数、参数取的名字。标识符不能是关键字或保留字。
关键字:是指 JS本身已经使用了的字,不能再用它们充当变量名、方法名。包括:break、case、catch、continue、default、delete、do、else、finally、for、function、if、in、instanceof、new、return、switch、this、throw、try、typeof、var、void、while、with 等。
保留字:实际上就是预留的“关键字”,意思是现在虽然还不是关键字,但是未来可能会成为关键字,同样不能使用它们当变量名或方法名。包括:boolean、byte、char、class、const、debugger、double、enum、export、extends、fimal、float、goto、implements、import、int、interface、long、mative、package、private、protected、public、short、static、super、synchronized、throws、transient、volatile 等。
注意:如果将保留字用作变量名或函数名,那么除非将来的浏览器实现了该保留字,否则很可能收不到任何错误消息。当浏览器将其实现后,该单词将被看做关键字,如此将出现关键字错误。
运算符(operator)也被称为操作符,是用于实现赋值、比较和执行算数运算等功能的符号。
在 JavaScript 中,递增(++)和递减( – )既可以放在变量前面,也可以放在变量后面。放在变量前面时,可以称为前置递增(递减)运算符,放在变量后面时,可以称为后置递增(递减)运算符。
注意:递增和递减运算符必须和变量配合使用。
++num 前置递增,就是自加1,类似于 num = num + 1,但是 ++num 写起来更简单。使用口诀:先自加,后返回值:
var num = 10;
alert(++num + 10); // 21
num++ 后置递增,就是自加1,类似于 num = num + 1 ,但是 num++ 写起来更简单。使用口诀:先返回原值,后自加 :
var num = 10;
alert(10 + num++); // 20
比较运算符(关系运算符)是两个数据进行比较时所使用的运算符,比较运算后,会返回一个布尔值(true / false)作为比较运算的结果。
、>=、<、<=略
console.log(18 == '18');
console.log(18 === '18');
逻辑运算符是用来进行布尔值运算的运算符,其返回值也是布尔值。
||、&&、!分别表示逻辑或、与、非。
短路运算(逻辑中断),当有多个表达式(值)时,左边的表达式值可以确定结果时,就不再继续运算右边的表达式的值;
表达式1 && 表达式2
console.log( 123 && 456 ); // 456
console.log( 0 && 456 ); // 0
console.log( 123 && 456 && 789 ); // 789
表达式1 || 表达式2
console.log( 123 || 456 ); // 123
console.log( 0 || 456 ); // 456
console.log( 123 || 456 || 789 ); // 123
用来把数据赋值给变量的运算符。=、+=、-=、*=、/=、%=,复合赋值运算符,先计算结果再赋值。
赋值表达式的值为最终赋值的那个值。
console.log(value = 10); // 10
优先级 | 运算符 | 顺序 |
---|---|---|
1 | 小括号 | () |
2 | 一元运算符 | ++、–、! |
3 | 算术运算符 | 先*、/、%后+、- |
4 | 关系运算符 | >、>=、<、<= |
5 | 相等运算符 | == 、!= 、=== 、!== |
6 | 逻辑运算符 | 先&& 后 ` |
7 | 赋值运算符 | = |
8 | 逗号运算符 | , |
注意:
if语句、三元运算符同c语言,略。
switch语句类似c语言,匹配是与 case 的值做全等(===) 。
for、while、do…while三种类型的循环语句同c语言,略。
数组是指一组数据的集合,其中的每个数据被称作元素,在数组中可以存放任意类型的元素。数组是一 种将一组数据存储在单个变量名下的优雅方式。
创建数组的方式:
var arr1 = new Array();
var arr2 = [1, '1', true, undefined, null];
数组可以通过索引来访问、设置、修改对应的数组元素:
arr1[0] = 1;
console.log(arr1);
console.log(arr2[1]);
arr2[1] = '你好';
console.log(arr2);
使用“数组名.length”可以访问数组元素的数量(数组长度):
console.log(arr2.length);
遍历数组,利用循环和length属性可以遍历数组,在此略。
length 属性是可读写的:
arr2.length = 6;
console.log(arr2);
console.log(arr2[5]);
arr2.length = 3;
console.log(arr2);
可以通过修改数组索引的方式追加数组元素,如果索引大于length,那么空缺的位置会以undefined填充:
arr2[4] = 4;
console.log(arr2[3]);
console.log(arr2);
不能直接给数组名赋值,否则会覆盖掉以前的数据:
arr2 = 1;
console.log(arr2);
冒泡排序案例:
var arr = [3, 2, 5, 6, 1];
for (var i = 0; i < arr.length - 1; i++) {
for (var j = i + 1; j < arr.length; j++) {
if (arr[i] > arr[j]) {
var temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
console.log(arr);
函数就是封装了一段可被重复调用执行的代码块。通过此代码块可以实现大量代码的重复使用。
申明函数:
function 函数名() {
//函数体代码
}
调用函数:
函数名();
在声明函数时,可以在函数名称后面的小括号中添加一些参数,这些参数被称为形参,而在调用该函数时, 同样也需要传递相应的参数,这些参数被称为实参。
// 带参数的函数声明
function 函数名(形参1, 形参2 , 形参3...) { // 可以定义任意多的参数,用逗号分隔
// 函数体
}
// 带参数的函数调用
函数名(实参1, 实参2, 实参3...);
形参与实参个数不匹配:
// 函数参数
function sum(num1, num2) {
console.log(num1 + num2);
}
sum(1, 2);
sum(1);
sum(1, 2, 3);
有的时候,会希望函数将值返回给调用者,此时通过使用 return 语句就可以实现。return 会终止函数,return 语句之后的代码不被执行:
// 函数返回值
function sum1(num1, num2) {
return num1 + num2;
}
console.log(sum1(1, 2));
return 只能返回一个值。如果用逗号隔开多个值,以最后一个为准:
function sum2(num1, num2) {
return 1, num1 + num2;
}
console.log(sum2(1, 2));
当不确定有多少个参数传递的时候,可以用 arguments 来获取。在 JavaScript 中,arguments 实际上 它是当前函数的一个内置对象。所有函数都内置了一个 arguments 对象,arguments 对象中存储了传递的 所有实参。arguments展示形式是一个伪数组,因此可以进行遍历。伪数组具有以下特点:
// arguments
function sum3() {
var result = 0;
for (var i = 0; i < arguments.length; i++) {
result += arguments[i];
}
return result;
}
console.log(sum3(1, 2, 3));
函数可以调用另外一个函数,因为每个函数都是独立的代码块,用于完成特殊任务,因此经常会用到函数相互调用的情况:
// 函数调用函数
function fn1() {
console.log('1');
fn2();
};
function fn2() {
console.log(2);
}
fn1();
// 函数调用函数
function fn1() {
console.log('1');
fn2();
};
function fn2() {
console.log(2);
}
fn1();
调用函数的代码既可以放到声明函数的前面,也可以放在声明函数的后面:
// 函数在函数申明前后都可以调用
fn3();
function fn3() {
console.log('fn3');
}
fn3();
函数可以作为值进行赋值、传递、返回:
// 函数作为值进行、传递与返回
var func = fn3;
fn3();
console.log(func);
function fn4(func) {
func();
return function () {
console.log('fn4');
};
}
fn4(fn3)();
函数可以没有名称,叫做匿名函数:
// 匿名函数
var func1 = function() {
console.log('匿名函数');
};
func1();
// 匿名函数简写
var func2 = (value) => {
return value * value
};
console.log(func2(10));
通常来说,一段程序代码中所用到的名字并不总是有效和可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。作用域的使用提高了程序逻辑的局部性,增强了程序的可靠性,减少了名字冲突。JavaScript(es6前)中的作用域有两种:
JS没有块级作用域,块作用域由 { } 包括。在其他编程语言中(如 java、c#等),在 if 语句、循环语句中创建的变量,仅仅只能在本 if 语句、本循环语句中使用。Js中没有块级作用域(在ES6之前)。
// Js中没有块级作用域(在ES6之前)
if (true) {
var a = 1;
console.log('a = ' + a);
}
console.log('a = ' + a);
在JavaScript中,根据作用域的不同,变量可以分为两种:全局变量、局部变量。
在全局作用域下声明的变量叫做全局变量(在函数外部定义的变量)
在局部作用域下声明的变量叫做局部变量(在函数内部定义的变量)
全局变量在任何一个地方都可以使用,只有在浏览器关闭时才会被销毁,因此比较占内存。局部变量只在函数内部使用,当其所在的代码块被执行时,会被初始化;当代码块运行结束后,就会被销毁,因此更节省内存空间。
只要是代码都一个作用域中,写在函数内部的局部作用域,未写在任何函数内部即在全局作用域中;如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域;根据在**[内部函数可以访问外部函数变量]**的这种机制,用链式查找决定哪些数据能被内部函数访问,就称作作用域链。
// 作用域链
function fn1() {
var num = 123;
function fn2() {
console.log(num); // 123
}
fn2();
}
var num = 456;
fn1();
function f1() {
var a = 2;
var b = '22';
f2();
function f2() {
var a = 3;
f3();
function f3() {
var a = 4;
console.log(a); // 4
console.log(b); // '22'
}
}
}
f1();
JavaScript 代码是由浏览器中的 JavaScript 解析器来执行的。JavaScript 解析器在运行 JavaScript 代码的时候分为两步:预解析和代码执行。
预解析会把变量和函数的声明在代码执行之前执行完成。
预解析也叫做变量、函数提升。
变量提升(变量预解析),变量的声明会被提升到当前作用域的最上面,变量的赋值不会提升。
console.log(num); // 结果是多少?
var num = 10; // ?
结果:undefined
注意:变量提升只提升声明,不提升赋值
函数提升,函数的声明会被提升到当前作用域的最上面,但是不会调用函数。
fn();
function fn() {
console.log('打印');
}
结果:控制台打印字符串 — ”打印“
注意:函数声明代表函数整体,所以函数提升后,函数名代表整个函数,但是函数并没有被调用!
函数表达式创建函数,会执行变量提升,此时接收函数的变量名无法正确的调用:
fn();
var fn = function() {
console.log('想不到吧');
}
结果:报错提示 ”fn is not a function"
解释:该段代码执行之前,会做变量声明提升,fn在提升之后的值是undefined;而fn调用是在fn被赋值为函数体之前,此时fn的值是undefined,所以无法正确调用。
在 JavaScript 中,对象是一组无序的相关属性和方法的集合,所有的事物都是对象,例如字符串、数值、数组、函数等。对象是由属性和方法组成的。
用数组保存数据的缺点是:数据只能通过索引值访问,开发者需要清晰的清楚所有的数据的排行才能准确地获取数据,而当数据量庞大时,不可能做到记忆所有数据的索引值。
为了让更好地存储一组数据,对象应运而生:对象中为每项数据设置了属性名称,可以访问数据更语义化,数据结构清晰,表意明显,方便开发者使用。
1、利用字面量创建对象:就是花括号 { } 里面包含了表达这个具体事物(对象)的属性和方法;{ } 里面采取键值对的形式表示
var star = {
name : 'pink',
age : 18,
sex : '男',
sayHi : function(){
alert('大家好啊~');
}
};
2、利用 new Object 创建对象
首先创建空对象,通过内置构造函数Object创建对象,此时andy变量已经保存了创建出来的空对象
var andy = new Obect();
然后给空对象添加属性和方法,通过对象操作属性和方法的方式,来为对象增加属性和方法
andy.name = 'pink';
andy.age = 18;
andy.sex = '男';
andy.sayHi = function(){
alert('大家好啊~');
}
注意:
3、利用构造函数创建对象
构造函数是一种特殊的函数,主要用来初始化对象,即为对象成员变量赋初始值,它总与 new 运算符一起使用。可以把对象中一些公共的属性和方法抽取出来,然后封装到这个函数里面。
function 构造函数名(形参1,形参2,形参3) {
this.属性名1 = 参数1;
this.属性名2 = 参数2;
this.属性名3 = 参数3;
this.方法名 = 函数体;
}
构造函数的调用格式
var obj = new 构造函数名(实参1,实参2,实参3)
注意事项:
构造函数,抽象了对象的公共部分,封装到了函数里面,它泛指某一大类(class)
创建对象,特指某一个,通过 new 关键字创建对象的过程也称为对象实例化
new关键字的作用:
对象中存储具体数据的 "键值对"中的 "键"称为对象的属性,即对象中存储具体数据的项
对象中存储函数的 "键值对"中的 "键"称为对象的方法,即对象中存储函数的项
访问对象的属性:
console.log(star.name) // 调用名字属性
console.log(star['name']) // 调用名字属性
调用对象的方法,对象.法名() ,注意这个方法名字后面一定加括号
star.sayHi(); // 调用 sayHi 方法,注意,一定不要忘记带后面的括号
属性是对象的一部分,而变量不是对象的一部分,变量是单独存储数据的容器:
方法是对象的一部分,函数不是对象的一部分,函数是单独封装操作的容器:
遍历对象,for…in 语句用于对数组或者对象的属性进行循环操作。
for (变量 in 对象名字) {
// 在此执行代码
}
语法中的变量是自定义的,它需要符合命名规范,通常我们会将这个变量写为 k 或者 key。
for (var k in obj) {
console.log(k); // 这里的 k 是属性名
console.log(obj[k]); // 这里的 obj[k] 是属性值
}
JavaScript 中的对象分为3种:自定义对象 、内置对象、 浏览器对象
内置对象就是指 JS 语言自带的一些对象,这些对象供开发者使用,并提供了一些常用的或是最基本而必要的功能(属性和方法),内置对象最大的优点就是帮助我们快速开发
JavaScript 提供了多个内置对象:Math、 Date 、Array、String等。
查找文档:可以通过MDN/W3C来查询,Mozilla 开发者网络(MDN)提供了有关开放网络技术(Open Web)的信息,包括 HTML、CSS 和万维网及 HTML5 应用的 API。
Math 对象不是构造函数,它具有数学常数和函数的属性和方法。跟数学相关的运算(求绝对值,取整、最大值等)可以使用 Math 中的成员。
属性、方法名 | 功能 |
---|---|
Math.PI | 圆周率 |
Math.floor() | 向下取整 |
Math.ceil() | 向上取整 |
Math.round() | 四舍五入版 就近取整 注意 -3.5 结果是 -3 |
Math.abs() | 绝对值 |
Math.max()/Math.min() | 求最大和最小值 |
Math.random() | 获取范围在[0,1)内的随机值 |
function getRandom(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
Date 对象和 Math 对象不一样,Date是一个构造函数,所以使用时需要实例化后才能使用其中具体方法和属性。Date 实例用来处理日期和时间
使用Date实例化日期对象,获取当前时间必须实例化:
var now = new Date();
获取指定时间的日期对象
var future = new Date('2019/5/1');
注意:如果创建实例时并未传入参数,则得到的日期对象是当前时间对应的日期对象
使用Date实例的方法:
通过Date实例获取总毫秒数,基于1970年1月1日(世界标准时间)起的毫秒数
// 实例化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();
使用构造函数Array创建非空数组,可以在创建数组时传入参数:
instanceof 可以判断一个对象是否是某个构造函数的实例:
var arr = [1, 23];
var obj = {};
console.log(arr instanceof Array); // true
console.log(obj instanceof Array); // false
Array.isArray()用于判断一个对象是否为数组,isArray() 是 HTML5 中提供的方法
var arr = [1, 23];
var obj = {};
console.log(Array.isArray(arr)); // true
push()末尾添加一个或多个元素,注意修改原数组,并返回新的长度:
// push()插入元素
var array = new Array();
array.push(1);
console.log(array);
array.push(2, 3);
console.log(array);
unshift()向数组的开头添加一个或更多元素,注意修改原数组,并返回新的长度:
// unshift()插入元素
array.unshift(0);
console.log(array);
array.unshift(-1, -2);
console.log(array);
pop()删除数组最后一个元素,把数组长度减1 无参数、修改原数组,返回它删除的元素的值:
// pop()删除数组最后一个元素
array.pop();
console.log(array);
shift()删除数组的第一个元素,数组长度减1 无参数、修改原数组,并返回第一个元素的值:
// shift()删除数组第一个元素
array.shift();
console.log(array);
splice()方法可以在数组指定位置添加元素或者删除元素,它会修改原数组,第一个参数代表数组索引2,第二个参数是删除元素的数量(0就是删除0个),第三个参数是添加的元素:
// splice()添加元素或者删除元素
array.splice(0, 1, -3);
console.log(array);
array.splice(2, 0, -1);
console.log(array);
slice()方法可在数组中截取元素,它返回一个新数组,不会改变原数组。第一个参数是截取开始的数组索引位置(包含此索引的元素),第二个参数是截取结束的位置(不包含此索引的元素):
// slice()截取子数组
console.log(array.slice(0, 2));
console.log(array);
indexOf()、lastIndexOf()检索数组中是否含有某个元素,如果有就返回元素第一个/最后一个下标(索引),如果没有则返回-1:
// indexOf()检索数组中是否含有某个元素
console.log(array.indexOf(0));
console.log(array.indexOf(10));
console.log(array.lastIndexOf(1));
console.log(array.lastIndexOf(10));
reverse()颠倒数组中元素的顺序,无参数,该方法会改变原来的数组 返回新数组:
console.log(array.reverse());
console.log(array);
sort()对数组的元素进行排序,该方法会改变原来的数组 返回新数组,如果传入“function(a,b){ return a-b;}”,则为升序,如果传入“function(a,b){ return b-a;}”,则为降序:
console.log(array.sort((a, b) => {
return a - b;
}));
console.log(array.sort((a, b) => {
return b - a;
}));
toString()把数组转换成字符串,逗号分隔每一项,返回一个字符串。
join(‘分隔符’)方法用于把数组中的所有元素转换为一个字符串,返回一个字符串:
console.log(array.toString());
console.log(array.join(','));
concat()连接两个数组,也可用于数组添加元素,它不会改变原数组而是返回一个新数组:
// concat()连接两个数组,也可用于数组添加元素
console.log(array.concat([4, 5]));
console.log(array);
console.log(array.concat(4, 5));
console.log(array);
map将数组中元素映射为一个新数组返回,不会改变原数组。
filter过滤器从数组中筛选出符合条件的元素作为一个新数组返回,不会改变原数组。
reduce遍历length - 1次,回调的第一个参数是累计结果的初始值为第一个元素,第二个参数当前值从第二个元素开始,不会改变原数组。
// map()、fliter()、reduce()
var mapA = array.map((value) => {
return value.toString();
});
console.log(mapA);
console.log(array);
var filterA = array.filter((value) => {
return value > 0;
});
console.log(filterA);
console.log(array);
var reduceA = array.reduce(function (previousValue, currentValue) {
return previousValue + currentValue;
});
console.log(reduceA);
console.log(array);
为了方便操作基本数据类型,JavaScript 还提供了三个特殊的引用类型:String、Number和 Boolean。
基本包装类型就是把简单数据类型包装成为复杂数据类型,这样基本数据类型就有了属性和方法。
// 下面代码有什么问题?
var str = 'andy';
console.log(str.length);
按道理基本数据类型是没有属性和方法的,而对象才有属性和方法,但上面代码却可以执行,这是因为
js 会把基本数据类型包装为复杂数据类型,其执行过程如下 :
// 1. 生成临时变量,把简单类型包装为复杂数据类型
var temp = new String('andy');
// 2. 赋值给我们声明的字符变量
str = temp;
// 3. 销毁临时变量
temp = null;
通过下面打印数据类型得出,变量赋值过程应该是不会进行包装,应该只有当使用属性和方法时才会进行包装:
var v = '1'
console.log(typeof v); // string
console.log(typeof new String(v)); // object
v = true;
console.log(typeof(v)); // boolean
console.log(typeof(new Boolean(v))); // object
v = 1;
console.log(typeof(v)); //number
console.log(typeof(new Number(v))); // object
字符串的不可变指的是里面的值不可变,虽然看上去可以改变内容,但其实是地址变了,内存中新开辟了一个内存空间。值类型数据的特征。
当重新给字符串变量赋值的时候,变量之前保存的字符串不会被修改,依然在内存中重新给字符串赋值,会重新在内存中开辟空间,这个特点就是字符串的不可变。由于字符串的不可变,在大量拼接字符串的时候会有效率问题。
字符串所有的方法,都不会修改字符串本身(字符串是不可变的),操作完成会返回一个新的字符串。
// 常用方法
var s = 'abcdefg'
console.log(s.split('c'));
console.log(s);
console.log(s.charAt(3));
console.log(s);
console.log(s.concat('1', '2'));
console.log(s);
console.log(s.slice(0, 2));
console.log(s);
console.log(s.substring(0, 2));
console.log(s);
console.log(s.substr(0, 2));
console.log(s);
s = '123321';
console.log(s.indexOf(1));
console.log(s.lastIndexOf(1));
s = ' 123 2 ';
console.log(s.trim());
console.log(s);
console.log(s.trimStart());
console.log(s.trimEnd());
console.log(s.trimLeft());
console.log(s.trimRight());
console.log(s);
s = 'aBc'
console.log(s.toLocaleUpperCase());
console.log(s);
console.log(s.toLocaleLowerCase());
console.log(s);
s = '123321';
console.log(s.replace('1', 'a'));
console.log(s);
console.log(s.replaceAll('1', 'a'));
console.log(s);
简单类型(基本数据类型、值类型):在存储时变量中存储的是值本身,包括string ,number,boolean,undefined,null
复杂数据类型(引用类型):在存储时变量中存储的仅仅是地址(引用),通过 new 关键字创建的对象(系统对象、自定义对象),如 Object、Array、Date等;
堆栈空间分配区别:
值类型变量的数据直接存放在变量(栈空间)中;引用类型变量(栈空间)里存放的是地址,真正的对象实例存放在堆空间中。
简单类型传参,函数的形参也可以看做是一个变量,当把一个值类型变量作为参数传给函数的形参时,其实是把变量在栈空间里的值复制了一份给形参,那么在方法内部对形参做任何修改,都不会影响到的外部变量。
function fn(a) {
a++;
console.log(a); // 11
}
var x = 10;
fn(x);
console.log(x); // 10
复杂数据类型传参,函数的形参也可以看做是一个变量,当把引用类型变量传给形参时,其实是把变量在栈空间里保存的堆地址复制给了形参,形参和实参其实保存的是同一个堆地址,所以操作的是同一个对象。
function Person(name) {
this.name = name;
}
function f1(x) { // x = p
console.log(x.name); // 2. 这个输出什么 ? 李四
x.name = "张三";
console.log(x.name); // 3. 这个输出什么 ? 张三
}
var p = new Person("李四");
console.log(p.name); // 1. 这个输出什么 ? 李四
f1(p);
console.log(p.name); // 4. 这个输出什么 ? 张三