一、初识JavaScript
1.JavaScript是什么
JavaScript(简称JS)
是世界上最流行的编程语言之一
是一个脚本语言,通过解释器进行
主要在客户端(浏览器)上运行,现在也可以基于node.js在服务器端运行
用于web(基于http、https协议)的网页用户交互的动作
JavaScript最初只是为了完成简单的表单验证(验证数据合法性),后来不小心就火了,当前JavaScript已经成为了一个通用的编程语言
JavaScript应用场景:
网页的开发(更复杂的特效和用户交互)
网页游戏开发
服务器开发(node.js)
桌面程序开发(Electron,VSCode就是这么来的)
手机app开发
2.JavaScript运行过程
1.编写的代码是保存在文件中的,也就是存储在硬盘(外存上)
2.双击.html文件浏览器(应用程序)就会读取文件,把文件内容加载到内存中(数据流向:硬盘=>内存)
3.浏览器会解析用户编写的代码,把代码翻译成二进制的,能让计算机识别的指令(解释器的工作)
4.得到的二进制指令会被CPU加载并执行(数据流向:内存=>CPU)
浏览器分为渲染引擎+JS引擎
渲染引擎: 解析html+CSS,俗称"内核"
JS引擎: 也就是JS解释器(可以解释执行js代码),典型的就是Chrome中内置的V8
JS引擎逐行读取js代码内容,然后解析成二进制指令,再执行
3.JavaScript的组成
ECMAScript(简称ES): JavaScript语法,es规定了js的语法,es有很多版本,我们说的是es5
DOM: 页面文档对象模型,对页面中的元素进行操作,用户交互,会动态的操作页面元素
BOM: 浏览器对象模型,对浏览器窗口进行操作(如:url,刷新按钮,前进,后退)
光有JS语法,只能写一些基础的逻辑流程
但是要想完成更复杂的任务,完成和浏览器以及页面的交互,那么就需要DOM API和BOM API
这主要指在浏览器端运行的JS,如果是运行在服务端的js,则需要使用node.js的API,就不太需要关注DOM和BOM
重要概念:ECMAScript
这是一套"标准",无论是啥样的JS引擎都要遵守这个标准来实现
二、前置知识
1.第一个程序
<script>
alert("你好!");
</script>
展示结果:
JavaScript代码可以嵌入到HTML的script标签中
2.JavaScript的书写形式
1.行内式
直接嵌入到html元素内部
<input type="button" value="点我一下" onclick="alert('haha')">
展示结果:
注意:JS中字符串常量可以使用单引号表示,也可以使用双引号表示
HTML中推荐使用双引号,JS中推荐使用单引号
所有html标签,以on开头的属性,几乎都是事件属性
事件:是用户交互时发生了某个事件,就会调用该事件绑定的js代码
2.内嵌式
写到script标签中
<script>
alert("haha!");
</script>
3.外部式
写到单独的.js文件中
<script src="hehe.js"></script>
hehe.js文件:
alert("hehe");
展示结果:
注意:这种情况下script标签中间不能写代码,必须空着(写了代码也不会执行)
适合代码多的情况
4.注释
单行注释//(建议使用)
多行注释/* */
使用ctrl+/切换注释
多行注释不能嵌套
三、输入输出
1.输入:prompt
弹出一个输入框,可以在窗口中输入一些内容
//弹出一个输入框
prompt("请输入您的姓名:");
展示结果:
2.输出:alert
弹出一个警示对话框,输出结果,提示一些信息
//弹出一个输出框
lert("hello");
展示结果:
3.输出:console.log
在控制台打印一个日志(供程序猿看),在开发者工具控制台显示一些内容,用于开发调试程序
//向控制台输出日志
console.log("这是一条日志");
注意:在VSCode中直接输入"log"再按tab键,就可以快速输入console.log
需要打开浏览器的开发者工具(F12)=>Console标签页,才能看到结果
这样的输出一般不是给普通用户看的,而是程序猿来看的
重要概念:日志
日志是程序员面试程序的重要手段
去医院看病,医生会让患者做各种检查,B超,CT等,此时得到一堆检测结果,这些结果普通人看不懂,但是医生能看懂,并且医生要通过这些信息来诊断病情
这些检测结果就是医生的“日志”
重要概念:.
console是一个js中的“对象”
.表示取对象中的某个属性或者方法,可以直观理解成“的”
console.log就可以理解成:使用“控制台”对象“的log方法
四、语法概览
JavaScript虽然一些设计理念和Java相去甚远,但是在基础语法层面上还是有一些相似之处的,有了Java的基础很容易理解JavaScript的一些基本语法
1.变量的使用
1.基本用法
创建变量(变量定义/变量声明/变量初始化)
var name='zhangsan';
var age=20;
1.var是JS中的关键字,表示这是一个变量
2.=在JS中表示“赋值”,相当于把数据放到内存的盒子中,=两侧建议有一个空格
3.每个语句最后带有一个;结尾,JS中可以省略;但是建议还是加上
4.注意,此处的分号为英文分号,JS中所有的标点都是英文标点
5.初始化的值如果是字符串,那么就要使用单引号或者双引号引起来
初始化的值如果是数字,那么直接赋值即可
使用变量
console.log(age);//读取变量内容
age = 30; //修改变量内容
为啥动漫中的角色都是要先喊出技能名字再真正释放技能?
那是因为变量要先声明才能使用
代码示例: 弹框提示用户输入信息,再弹框显示
var name=prompt("请输入姓名:");
var age=prompt("请输入年龄:");
var score=prompt("请输入分数:");
alert("您的姓名是:"+name+"\n"+"您的年龄是:"+age+"\n"+"您的分数是:"+score);
展示结果:
+表示字符串拼接,也就是把两个字符串首尾相接变成一个字符串
\n表示换行
JavaScript也可以使用let 变量名 = 值;
var和let只是作用域不同,两者都表示要定义变量
2.理解动态类型
1.JS的变量类型是程序运行过程中才确定的(运行到=语句才会确定类型)
var a = 10; //数字
var b = "hehe";//字符串
2.随着程序运行,变量的类型可能会发生改变(从一个类型变成另一个类型)
var a = 10;//数字
a = "hehe";//字符串
所以字符串+数值,会先把数值转换为字符串,再拼接两个字符串
console.log("hehe"+10);//hehe10
这一点和C,Java这种静态类型语言差异较大
C,C++,Java,Go等语言是静态类型语言,一个变量在创建的时候类型就确定了,不能在运行时发生改变
如果尝试改变,就会直接编译报错
五、基本数据类型
JS中内置的几种类型
number: 数字,不区分整数和小数
boolean: true真,false假
string: 字符串类型
undefined: 只有唯一的值undefined,表示未定义的值
null: 只有唯一的值null,表示空值
1.number数据类型
JS中不区分整数和浮点数,统一都使用“数字类型”来表示
1.数字进制表示
计算机中都是使用二进制来表示数据,而我们平时都是使用十进制
因为二进制在使用过程中不太方便(01太多造成混乱)
所以在日常使用二进制数字时往往使用八进制和十六进制来表示二进制数字
var a = 07; //八进制整数,以0开头
var b = 0xa; //十六进制整数,以0x开头
var c = 0b10; //二进制整数,以0b开头
注意:
一个八进制数字对应三个二进制数字
一个十六进制数字对应四个二进制数字(两个十六进制数字就是一个字节)
各种进制之间的转换,不需要手工计算,直接使用计算器即可
2.特殊的数字值
Infinity: 无穷大,大于任何数字,表示数字已经超过了JS能表示的范围
-Infinity: 负无穷大,小于任何数字,表示数字已经超过了JS能表示的范围
NaN: 表示当前的结果不是一个数字
var max=Number.MAX_VALUE;
console.log(max*2);
console.log(-max*2);
console.log('hehe'-10);
展示结果:
注意:
1.负无穷大和无穷小不是一回事,无穷小指无限趋近于0,值为1/Infinity
2.‘hehe’+10得到的不是NaN,而是‘hehe10’,会把数字隐式转成字符串,再进行字符串拼接
3.可以使用isNaN函数判定是不是一个非数字
console.log(isNaN(10));
console.log(isNaN('hehe'-10));
展示结果:
2.string字符串类型
1.基本规则
字符串字面值需要使用引号引起来,单引号双引号均可
var a = "haha";
var b = 'hehe';
var c = hehe; //运行出错
如果字符串中本来已经包含引号咋办?
2.转义字符
有些字符不方便直接输入,于是要通过一些特殊方法来表示
\n
\
\’
\"
\t
3.求长度
使用String的length属性即可
var a = 'hehe';
console.log(a.length);
var b = '哈哈';
console.log(b.length);
展示结果:
单位为字符的数量
4.字符串拼接
使用+进行拼接
var a = "my name is ";
var b = "zhangsan";
console.log(a+b);
注意:数字和字符串也可以进行拼接
var c = "my score is ";
var d = 100;
console.log(c+d);
注意,要认准相加的变量到底是字符串还是数字
console.log(100+100); //200
console.log('100'+100); //100100
3.boolean布尔类型
表示“真”和“假”
boolean原本是数学的概念(布尔代数)
在计算机中boolean意义重大,往往要搭配条件/循环完成逻辑判断
Boolean参与运算时当作1和0来看待
console.log(true+1);
console.log(false+1);
展示结果:
这样的操作其实是不科学的,实际开发中不应该这么写
4.undefined未定义数据类型
如果一个变量没有被初始化过,结果就是undefined,是undefined类型
var a;
console.log(a);
展示结果:
undefined和字符串进行相加,结果进行字符串拼接
console.log(a+"10");
undefined和数字进行相加,结果为NaN
console.log(a+10);
5.null空值类型
null表示当前的变量是一个“空值”
var b=null;
console.log(b+10);
console.log(b+"10");
注意:
null和undefined都表示取值非法的情况,但是侧重点不同
null表示当前的值为空(相当于有一个空的盒子)
undefined表示当前的变量未定义(相当于连盒子都没有)
六、数组
1.创建数组
使用new关键字创建
//Array的A要大写
var arr=new Array();
使用字面量方式创建[常用]
var arr=[];
var arr2=[1,2,'haha',false]; //数组中保存的内容称为“元素”
注意:JS的数组不要求元素是相同类型
这一点和C,C++,Java等静态类型的语言差别很大,但是Python,PHP等动态类型
、言也是如此
2.获取数组元素
使用下标的方式访问数组元素(从0开始)
var arr=['图图','小美','壮壮'];
console.log(arr);
console.log(arr[0]);
console.log(arr[1]);
console.log(arr[2]);
arr[2]='王子';
console.log(arr);
展示结果:
如果下标超出范围读取元素,则结果为undefined
console.log(arr[3]);
console.log(arr[-1]);
展示结果:
注意:不要给数组名直接赋值,此时数组中的所有元素都没了
相当于本来arr是一个数组,重新赋值后变成字符串了
var arr=['图图','小美','壮壮'];
arr='王子';
3.新增数组元素
1.通过修改length新增
相当于在末尾新增元素,新增的元素默认值为undefined
var arr=[9,5,2,7];
arr.length=6;
console.log(arr);
console.log(arr[4],arr[5]);
展示结果:
2.通过下标新增
如果下标超出范围赋值元素,则会给指定位置插入新元素
var arr=[];
arr[2]=10;
console.log(arr);
展示结果:
此时这个数组[0]和[1]都是undefined
3.使用push进行追加元素
代码示例:给定一个数组,把数组中的奇数放到一个newArr中
var arr=[9,5,2,7,3,6,8];
var newArr=[];
for(var i=0;i<arr.length;i++){
if(arr[i]%2==1){
newArr.push(arr[i]);
}
}
console.log(newArr);
展示结果:
4.删除数组中的元素
1.使用splice方法删除元素
var arr=[9,5,2,7];
//第一个参数表示从下标为2的位置开始删除,第二个参数表示要删除的元素个数是1个
arr.splice(2,1);
console.log(arr);
展示结果:
目前咱们已经用到了数组中的一些属性和方法
arr.length,length使用的时候不带括号,此时length就是一个普通的变量(称为成员变量,也叫属性)
arr.push(),arr.splice()使用的时候带括号,并且可以传参数,此时是一个函数(也叫做方法)
七、函数
1.语法格式
//创建函数/函数声明/函数定义
function 函数名(形参列表) {
函数体
return 返回值;
}
//函数调用
函数名(参数列表) //不考虑返回值
返回值 = 函数名(实参列表) //考虑返回值
注意:函数声明中,没有Java中的返回类型,return语法可有可无
函数定义并不会执行函数体内容,必须要调用才会执行,调用几次就会执行几次
function hello() {
console.log("hello");
}
//如果不调用函数,则没有执行打印语句
hello();
调用函数的时候进入函数内部执行,函数结束时回到调用位置继续执行,可以借助调试器来观察
函数的定义和调用的先后顺序没有要求(这一点和变量不同,变量必须先定义再使用)
2.关于参数个数
实参和形参之间的个数可以不匹配,但是实际开发一般要求形参和实参个数要匹配
1)如果实参个数比形参个数多,则多出的参数不参与函数运算
sum(10,20,30); //30
2)如果参数个数比形参个数少,则此时多出来的形参值为undefined
sum(10); //NaN,相当于num2为undefined
JS的函数传参比较灵活,这一点和其他语言差别较大,事实上这种灵活往往不是好事
3.函数表达式
另外一种函数的定义方式
var add=function() {
var sum=0;
for (var i=0;i<arguments.length;i++){
sum+=arguments[i];
}
return sum;
}
console.log(add(10,20));
console.log(add(1,2,3,4));
console.log(typeof add);
展示结果:
此时形如function() {}这样的写法定义了一个匿名函数,然会将这个匿名函数用一个变量来表示,后面就可以通过这个add变量来调用函数了
函数内默认的内置对象arguments,可以获取调用函数时,传入的参数列表(数组)
JS中函数是一等公民,可以用变量保存,也可以作为其他函数的参数或者返回值
4.作用域
某个标识符名字在代码中的有效范围
再ES6标准之前,作用于主要分成两个
全局作用域: 在整个script标签中,或者单独的js文件中生效
局部作用域/函数作用域: 在函数内部生效
var num=10;
console.log(num);
function test1() {
//局部变量
var num=20;
console.log(num);
}
function test2() {
//局部变量
var num=30;
console.log(num);
}
test1();
test2();
console.log(num);
展示结果:
在< script >标签中,或js文件中,直接写变量名=值,为全局作用域
function test() {
num=100;
}
test();
console.log(num);
展示结果:
另外,很多语言的局部变量作用域是按照代码块(大括号)来划分的,JS在ES6之前不是这样的
了解:
1.var,let在函数内定义的,外边不可见
2.var在条件、循环控制语句中,外部可见
3.let在条件、循环控制语句中,外部不可见(let作用域只在本花括号)
5.作用域链
背景:
函数可以定义在函数内部
内层函数可以访问外层函数的局部变量
内部函数可以访问外部函数的变量,采用的是链式查找的方式,从内到外依次进行查找
var num=1;
function test1() {
var num=10;
function test2() {
var num=20;
console.log(num);
}
test2();
}
test1();
展示结果:
执行console.log(num)的时候,会先在test2的局部作用域中查找num,如果没找到,则继续去test1中查找,如果还没找到,就去全局作用域查找
八、对象
1.基本概念
对象是指一个具体的事物
"电脑"不是对象,而是一个泛指的类别,而“我的联想笔记本”就是一个对象
在JS中,字符串、数值、数组、函数都是对象
每个对象中包含若干的属性和方法
属性: 事物的特征
方法: 事物的行为
对象需要保存的属性有多个,虽然数组也能用于保存多个数据,但是不够好
假如表示一个学生信息(姓名胡图图,身高175cm,体重130斤)
var student =[‘胡图图’,175,130];
但是这种情况下到底175和170谁表示身高,谁表示体重,就容易分不清
JavaScript的对象和Java的对象概念上基本一致,只是具体的语法表现形式差别较大
1.使用字面量创建对象[常用]
使用{}创建对象
var a = {};//创建了一个空的对象
var student={
name: '胡图图',
height: 175,
weight: 130,
sayHello: function() {
console.log("hello");
}
};
1.使用{}创建对象
2.属性和方法使用键值对的形式来组织
3.键值对之间使用,分割,最后一个属性后面的,可有可无
4.键和值之间使用:分割
5.方法的值是一个匿名函数
使用对象的属性和方法:
//1.使用 . 成员访问运算符来访问属性,‘,’可以理解为”的“
console.log(student.name);
//2.使用[]访问属性,此时属性需要加上引号
console.log(student['height']);
//3.调用方法,别忘记加上()
student.sayHello();
2.使用new Object创建对象
var student = new Object();//和创建数组类似
student.name="胡图图";
student.height=175;
student['weight']=130;
student.sayHello=function () {
console.log("hello");
}
console.log(student.name);
console.log(student['weight']);
student.sayHello();
展示结果:
注意:
使用{}创建的对象也可以随时使用student.name=“胡图图”,这样的方式来新增属性
3.使用构造函数创建对象
前面的创建对象方式只能创建一个对象,而使用构造函数可以很方便的创建多个对象
例如:创建几个猫咪对象
var mimi = {
name: "咪咪",
type: "中华田园猫",
miao: function () {
console.log("喵");
}
};
var xiaohei = {
name: "小黑",
type: "波斯猫",
miao: function () {
console.log("喵呜");
}
};
var ciqiu = {
name: "刺球",
type: "金渐层",
miao: function () {
console.log("咕噜噜");
}
};
此时写起来就比较麻烦,使用构造函数可以把相同的属性和方法的创建提取出来,简化开发过程
基本语法
function 构造函数名(形参) {
this.属性 = 值;
this.方法 = function...
}
var obj = new 构造函数名(实参);
注意:
1.在构造函数内部使用this关键字来表示当前正在构造的对象
2.构造函数的函数名首字母一般是大写的
3.构造函数的函数名可以是名词
4.构造函数不需要return
5.创建对象的时候必须使用new关键字
this相当于“我”
使用构造函数重新创建猫咪对象
function Cat(name,type,sound) {
this.name = name;
this.type = type;
this.miao = function () {
console.log(sound);//别忘了作用域的链式访问规则
}
}
var mimi = new Cat('咪咪','中华田园猫','喵');
var xiaohei = new Cat('小黑','波斯猫','喵呜');
var ciqiu = new Cat('刺球','金渐层','咕噜噜');
console.log(mimi);
mimi.miao();
2.理解new关键字
new的执行过程:
1.先在内存中创建一个空的对象{}
2.this指向刚才的空对象(将上一步的对象作为this的上下文)
3.执行构造函数的代码,给对象创建属性和方法
4.返回这个对象(构造函数本身不需要return,由new代劳了)
3.JavaScript的对象和Java的对象的区别
1.JavaScript没有“类”的概念
对象其实就是“属性”+“方法”
类相当于把一些具有共性的对象的属性和方法单独提取了出来,相当于一个“月饼模子”。
在JavaScript中的“构造函数”也能起到类似的效果
而且即使不用构造函数,也可以随时通过{}的方式指定出一些对象
在ES6中也引入了class关键字,就能按照类似于java的方式创建类和对象了
2.JavaScript对象不区分“属性”和“方法”
JavaScript中的函数是“一等公民”,和普通的变量一样,存储了函数的变量能够通过()来进行调用执行
3.JavaScript对象没有private/public等访问控制机制
对象中的属性都可以被外界随意访问
4.JavaScript对象没有“继承”
继承本质就是“让两个对象建立关联”,或者说是让一个对象能够重用另一个对象的属性/方法,JavaScript中使用 “原型”机制 实现类似的效果
5.JavaScript没有“多态”
多态的本质在于“程序员不必关注具体的类型,就能使用其中的某个方法”
C++/Java等静态类型的语言对于类型的约束和校验比较严格,因此通过子类继承父类,并重写父类的方法的方式来实现多态的效果
但是 在JavaScript中本身就支持动态类型,程序员在使用对象的某个方法的时候本身也不需要对对象的类型作出明确区分,因此并不需要在语法层面上支持多态