JavaScript的基础语法包括变量声明和赋值、数据类型、运算符、控制流程和函数等方面:
在变量声明和赋值时,有一些需要注意的地方,下面列举了一些常见的情况:
变量命名规则:
声明变量:
var
关键字可以声明一个变量,例如:var x;
。赋值变量:
=
为变量赋值。var x = 5;
。变量提升(Hoisting):
undefined
。console.log(x); // 输出:undefined
var x = 5;
块级作用域变量(ES6新增):
let
或const
关键字可以声明块级作用域的变量。{
let y = 10; // 块级作用域变量
const z = 15; // 块级作用域常量
console.log(y); // 输出:10
}
console.log(y); // 报错:y is not defined
常量声明:
const
关键字声明的变量是一个常量,一旦赋值后就不能更改。const PI = 3.14; // 声明一个常量PI并赋值为3.14
PI = 3.14159; // 报错:Assignment to constant variable.
变量作用域:
数字(Number):
字符串(String):
用于表示文本数据,由单引号(')或双引号(")括起来。
字符串是不可变的,即一旦创建就不能修改。对字符串的操作通常会返回一个新的字符串。
布尔值(Boolean):
空(Null):
表示一个空值。
null是一个特殊的关键字,不是对象也不是未定义(undefined)。
使用typeof运算符检测null会返回"object",这是一个历史遗留的错误。
未定义(Undefined):
表示未赋值。
使用typeof运算符检测未定义的变量会返回"undefined"。
避免显式地将变量设为undefined,如果需要清空一个变量的值,可以使用null。
对象(Object):
表示复杂的数据结构,可以存储多个相关属性和方法。对象由键值对集合组成。
对象是引用类型,赋值时实际上是复制了引用而不是对象本身。
使用点(.)或方括号([])可以访问对象的属性。
数组(Array):
表示一个有序的集合,可以存储多个值。
数组是一种特殊的对象,使用数字索引(从0开始)来访问元素。
可以使用length属性获取数组的长度。
JavaScript中的数组是一个有序的数据集合,可以包含任意类型的元素。在JavaScript中,可以使用数组字面量或Array()构造函数来创建数组。
以下是一些常见的操作和用法:
创建数组:
const arr = [1, 2, 3]; // 使用数组字面量创建数组 const arr2 = new Array(); // 使用Array()构造函数创建一个空数组 const arr3 = new Array(1, 2, 3); // 使用Array()构造函数创建一个带有初始值的数组
访问和修改元素:
console.log(arr[0]); // 输出数组的第一个元素,索引从0开始 arr[1] = 5; // 修改数组的第二个元素为5
数组的长度:
console.log(arr.length); // 输出数组的长度
向数组末尾添加元素:
arr.push(4); // 在数组的末尾添加一个元素4
从数组末尾删除元素:
arr.pop(); // 删除数组的最后一个元素
向数组开头添加元素:
arr.unshift(0); // 在数组的开头添加一个元素0
从数组开头删除元素:
arr.shift(); // 删除数组的第一个元素
迭代数组:
arr.forEach(function(element) { console.log(element); }); // 遍历数组并输出每个元素
数组切片:
const slicedArr = arr.slice(1, 3); // 返回一个新的数组,包含索引从1到3(不包括3)的元素
注意:
索引和长度:JavaScript数组的索引从0开始,而数组的长度是基于索引的最大值加1。例如,一个长度为3的数组有索引0、1、2,对应三个元素。
类型灵活:JavaScript数组可以包含不同类型的元素,甚至可以同时包含字符串、数字、对象等多种类型。
动态性:JavaScript数组的长度是可变的,可以随时添加或删除元素,并且可以根据需要自动调整大小。
循环遍历:可以使用for循环、forEach()、map()、filter()等方法来遍历数组的元素。
注意数组拷贝:当将一个数组赋值给另一个变量时,实际上是将引用传递。如果修改其中一个数组,另一个数组也会受到影响。如果需要创建一个新的独立副本,可以使用slice()或spread运算符(…)进行浅拷贝(克隆),或使用深拷贝方法(如JSON.parse(JSON.stringify(arr)))进行深拷贝。
注意数组边界:在访问数组元素时,要确保索引不超出数组的范围,否则会抛出"Index out of range"错误。
数组的比较:JavaScript中的数组比较是基于引用的,而不是内容。即使两个数组具有相同的元素,但它们不会被认为是相等的,除非它们引用相同的内存空间。
函数(Function):
表示可重复执行的代码块,可以接收参数,并返回一个值。
函数可以作为变量、参数、返回值、对象属性等。
在JavaScript中,函数也是对象。
日期(Date):
表示日期和时间。
JavaScript使用内置的Date对象来表示日期和时间。
Date对象提供了各种方法来操作和格式化日期。
正则表达式(RegExp):
表示用于模式匹配的文本字符串。
正则表达式是对字符串进行模式匹配和替换的强大工具。
在JavaScript中,正则表达式由正则表达式字面量或RegExp对象表示。
示例:
var num = 5; // 数字类型
var str = "Hello"; // 字符串类型
var bool = true; // 布尔类型
var empty = null; // 空类型
var undef = undefined; // 未定义类型
var obj = {name: "John", age: 25}; // 对象类型
var arr = [1, 2, 3]; // 数组类型
JavaScript提供了一系列的运算符,用于在表达式中执行各种操作。以下是一些常见的JavaScript运算符:
- 加法(+):对两个值进行相加。
- 减法(-):从第一个值中减去第二个值。
- 乘法(*):将两个值相乘。
- 除法(/):将第一个值除以第二个值。
- 取余(%):返回第一个值除以第二个值的余数。
- 赋值(=):将右侧的值赋给左侧的变量。
- 加等于(+=):将右侧的值与左侧的变量相加,并将结果赋给左侧的变量。
- 减等于(-=):从左侧的变量中减去右侧的值,并将结果赋给左侧的变量。
- 乘等于(*=):将左侧的变量与右侧的值相乘,并将结果赋给左侧的变量。
- 除等于(/=):将左侧的变量除以右侧的值,并将结果赋给左侧的变量。
- 取余等于(%=):将左侧的变量与右侧的值取余,并将结果赋给左侧的变量。
- 等于(==):检查两个值是否相等。
- 全等于(===):检查两个值是否严格相等(值和类型都相等)。
- 不等于(!=):检查两个值是否不相等。
- 不全等于(!==):检查两个值是否严格不相等。
- 大于(>)、小于(<)、大于等于(>=)、小于等于(<=):用于比较两个值的大小关系。
- 逻辑与(&&):仅当两个操作数都为真时,结果才为真。
- 逻辑或(||):当至少有一个操作数为真时,结果为真。
- 逻辑非(!):对操作数取反,如果是真则变为假,如果是假则变为真。
- 三元运算符(条件运算符)根据条件选择返回不同的值。
- 语法:条件 ? 结果1 : 结果2
注意事项:
类型转换:
短路评估:
隐式类型转换:
运算符优先级和结合性:
NaN(非数值):
JavaScript的控制流程由条件语句和循环语句组成,用于根据条件的真假和重复执行代码块。
条件语句根据给定的条件来执行不同的代码块。
if (条件) {
// 执行语句
}
可以使用逻辑运算符(如&&、||)和比较运算符(如==、!=)来构建复杂的条件。
if (条件) {
// 执行语句1
} else {
// 执行语句2
}
switch (表达式) {
case 值1:
// 执行语句1
break;
case 值2:
// 执行语句2
break;
default:
// 执行默认语句
break;
}
如果表达式的值与某个case的值相等,则执行该case的代码块,并使用break语句跳出switch语句。如果没有匹配的case,则执行default的代码块。
示例:
let num = 10;
if (num > 0) {
console.log("num是一个正数");
} else if (num < 0) {
console.log("num是一个负数");
} else {
console.log("num是零");
}
// 输出:num是一个正数
let day = "Monday";
switch (day) {
case "Monday":
console.log("星期一");
break;
case "Tuesday":
console.log("星期二");
break;
case "Wednesday":
console.log("星期三");
break;
default:
console.log("其他日子");
break;
}
// 输出:星期一
循环语句用于多次执行相同或类似的代码块。
for (初始化; 条件; 步长) {
// 执行语句
}
其中,初始化用于设置循环变量的初始值,条件用于判断是否继续循环,步长用于更新循环变量的值。
while (条件) {
// 执行语句
}
do {
// 执行语句
} while (条件);
即使条件为假,do-while循环至少会执行一次。
示例:
for (let i = 0; i < 5; i++) {
console.log(i);
}
// 输出:0, 1, 2, 3, 4
let num = 0;
while (num < 5) {
console.log(num);
num++;
}
// 输出:0, 1, 2, 3, 4
let num = 0;
do {
console.log(num);
num++;
} while (num < 5);
// 输出:0, 1, 2, 3, 4
for (let i = 1; i <= 10; i++) {
if (i % 3 === 0) {
continue; // 跳过3的倍数
}
if (i === 7) {
break; // 结束循环
}
console.log(i);
}
// 输出:1, 2, 4, 5, 6
let count = 0;
while (true) {
console.log(count);
count++;
if (count === 5) {
break; // 结束无限循环
}
}
// 输出:0, 1, 2, 3, 4
注意事项:
函数是一种在编程中用于封装代码的机制。它是一段可重复使用的代码块,通过给它一个名称,可以在程序中多次调用该代码块,从而实现代码的模块化和复用。
函数由以下几个主要组成部分:
函数名:函数具有一个名称,用于标识和调用函数。函数名应具有描述性,能够清晰地表达函数的功能。
参数:函数可以接受零个或多个参数(也称为形式参数)。参数是函数在调用时传递给函数内部的值。参数可以在函数内部使用,用于执行特定的操作和计算。参数允许将数据传递到函数中,从而使函数更加通用和灵活。
函数体:函数体包含了函数要执行的一系列语句或代码块。函数体是函数的主要执行逻辑,在函数调用时被执行。
返回值:函数可以返回一个值作为其执行结果。返回值使用return语句定义,并在函数体中指定要返回的值。返回值可以使用在函数调用表达式中进行进一步处理和使用。
函数的好处包括:
函数的定义和调用是使用函数的基本步骤。下面是函数的定义和调用的说明:
function
来定义一个函数。语法:
function functionName() {
// 函数代码块
}
示例:
function greet() {
console.log("Hello, world!");
}
()
来实现。语法:
functionName();
示例:
greet(); // 输出:Hello, world!
语法:
function functionName(parameter1, parameter2, ...) {
// 函数代码块
}
示例:
function greet(name) {
console.log("Hello, " + name + "!");
}
greet("John"); // 输出:Hello, John!
return
语句指定要返回的值。语法:
function functionName() {
// 函数代码块
return value;
}
示例:
function add(a, b) {
return a + b;
}
let result = add(3, 5);
console.log(result); // 输出:8
总结:
function
关键字,给函数命名,并编写函数体内的代码。()
,如果有参数,可以在括号中传递参数值。递归指的是函数在其自身内部调用自己的一种技术或方法。换句话说,递归是一种通过不断调用自己来解决问题的求解方法。
递归函数包含两个主要部分:
基本情况(Base case):递归函数中必须包含一个或多个基本情况,以防止无限递归。基本情况是函数停止递归的条件。
递归调用(Recursive call):递归函数调用自身来解决规模更小的子问题,直到达到基本情况为止。
递归的实现可以更简洁和优雅地解决一些问题,例如:
递归的思想是将大问题划分为与原问题相似但规模更小的子问题,并反复调用函数来解决这些子问题,直到达到基本情况从而结束递归。
注意:
如果递归没有正确设置基本情况或递归调用的条件,它可能会导致无限递归,这会使得程序运行时陷入无限循环,并最终耗尽可用的系统资源。
作用域:
{}
封闭的代码块内声明的变量,只能在该块级作域内部访问。闭包:
闭包的应用场景包括:
立即执行函数(Immediately Invoked Function Expression,简称IIFE)是一种 JavaScript 中的函数表达式,它可以立即执行而无需显式调用。
常见的 IIFE 格式如下:
(function() {
// 函数体
})();
基本原理和用法如下:
IIFE 的主要用途是创建一个独立的作用域,并且避免变量污染全局作用域。由于 IIFE 的执行结果不会被保存在全局变量中,所以其内部声明的变量不会影响到全局作用域。
示例:
(function() {
var name = "John";
console.log("Hello, " + name); // 输出:Hello, John
})();
console.log(name); // 报错,name 不在全局作用域中可见
此外,IIFE 还可以接收参数:
(function(message) {
console.log(message);
})("Hello, World!"); // 输出:Hello, World!
通过传递参数,可以在立即执行的函数中使用外部的值。
var a = Number(prompt("请输入第一个数字"));
var b = Number(prompt("请输入第二个数字"));
var sum = a + b;
alert('第一个数字'+a+'加上第二个数字'+b+'等于'+ sum);
var a = Number(prompt("请输入年份:"));
// 1.能被4整除,但是不能被100整除
// 2.能被100整除,也能被400整除
// 是闰年输出为true,不是输出为false
alert(a%4==0 && a%100!=0 || a%100==0 && a%400==0);
var height = Number(prompt("请输入你的身高(m)"));
var weight = Number(prompt("请输入你的体重(公斤)"));
var bmi = weight / Math.pow(height,2);
alert('您的BMI指数为:'+bmi);
if(bmi < 18.5){
alert('偏瘦');
}else if(bmi < 24){
alert('正常');
}else if(bmi < 28){
alert('过胖');
}else if(bmi < 32){
alert('肥胖');
}else{
alert('非常肥胖');
}
//水仙花数:一个 n 位数等于其每个数字的立方和
//例如:1^3 + 5^3 + 3^3 = 153
var n = Number(prompt("请输入一个三位数"));
// 对用户输入的值进行合法的验证
if(!isNaN(n) && 100 <=n && n<=999){
var a = Math.floor(n/100);
var b = Math.floor((n /10) % 10);
var c = n % 10
if(Math.pow(a,3)+Math.pow(b,3)+Math.pow(c,3)==n){
alert('这个数是水仙花数');
}else{
alert('这个数不是水仙花数')
}
}else{
alert('您输入的数字不合法')
}
//产生一个随机数,2-99
var num = parseInt(Math.random()*98)+2;
var min = 1;
var max =100;
//为了不断地重复执行询问,必须使用死循环
while(true){
// 用户输入一个数字
var n = Number(prompt('请猜测数字'+min+'~'+max));
//验证用户输入的语句是否在范围内
if(n<min || n>max){
//不在区间内,直接放弃这次循环,开启下一次迭代
alert('您输入的数字不在范围内!');
continue;
if(n<num){
alert('您输入的数字偏小');
min = n
}else if(n>num){
alert(('您输入的数字偏大'));
max = n
}else{
alert(('恭喜您,猜对了!'));
break;
}
}
}
// 鸡兔同笼问题,头:35 脚:94
//方法1:假设小鸡有a只,兔子有b只
// for(var a = 0;a <= 35; a++){
// for(var b = 0; b <= 35 ;b++){
// if(a + b == 35 && 2 * a + 4 * b == 94){
// console.log('小鸡有'+a+'只,兔子有'+b+'只');
// }
// }
// }
// 方法2:假设小鸡有a只,兔子就是(35-a)只
for( var a = 0; a <= 35; a++){
var b = 35 - a;
if(a*2+b*4 == 94){
console.log('小鸡有'+a+'只,兔子有'+b+'只');
}
}
// 穷举法
outer: for(var i = 2; i <=100; i++){
//内层循环从2开始尝试除i,如果能够整除,说明它不是质数,就可以筛选下一个数字了
for(var j = 2 ;j < i; j++){
if(i%j == 0){
// 说明数字i不是质数
//要给外层循环加上label,然后在continue的后面加上label,这样就表示立即开始迭代外层for循环的下一个数字了,而不是内层for循环
continue outer;
}
}
// 能够遇见这条语句的数字i,一定是质数,否则就被continue略过了
console.log(i)
}
// 题目:随机两个变量,dx和dy,它们都在[-4,4]之间随机取值,但是不能都为0
do{
//得到[a,b]区间的整数,公式: parseInt(Math.random()*(b-a+1))+a
var dx = parseInt(Math.random()*9)-4;
var dy = parseInt(Math.random()*9)-4;
}while(dx==0 && dy==0)
// 只要出循环,就保证dx和dy不都是0
console.log(dx,dy);
// 用莱布尼茨级数估算圆周率
// Π = 2 * (1 + 1/3 + (1*2)/(3*5) + (1*2*3)/(3*5*7) +(1*2*3*4)/(3*5*7*9)+(1*...n)/(3*5...*(2n+1))
//累加器,就是最后的答案
var sum = 0;
// 累乘器,用来制作每一项,制作出来了的那个项,要往累加器中累加
var item = 1;
// 让用户输入n
var n = Number(prompt('请输入数字n'));
for(var i = 1; i < n+1; i++){
// 要先制作出这一项,这一项怎么制作?要使用累乘器,item就是小车箱
item *= i/(2 * i +1);
console.log(item);
sum += item;
}
//显示结果
alert((1+sum)*2);
// 用莱布尼茨级数估算圆周率
// Π = 2 * (1 + 1/3 + (1*2)/(3*5) + (1*2*3)/(3*5*7) +(1*2*3*4)/(3*5*7*9)+(1*...n)/(3*5...*(2n+1))
//累加器,就是最后的答案
var sum = 0;
// 累乘器,用来制作每一项,制作出来了的那个项,要往累加器中累加
var item = 1;
// 让用户输入n
var n = Number(prompt('请输入数字n'));
for(var i = 1; i < n+1; i++){
// 要先制作出这一项,这一项怎么制作?要使用累乘器,item就是小车箱
item *= i/(2 * i +1);
console.log(item);
sum += item;
}
//显示结果
alert((1+sum)*2);
var arr = [3,4,5,2,5,,2,89];
// 结果数组
var result = [];
//遍历原数组
for(var i=0;i<arr.length;i++){
//随机选择一项的下标,数组的下标0~arr.length-1;
//random公式: [a,b]区间的随机数是parseInt(Math.random()*b-a+1)+a
var n = parseInt(Math.random()* arr.length);
//把这项推入数组
result.push(arr[n]);
//删除这项,防止重复被随机到
arr.splice(n,1);
}
console.log(result);
var arr = [1,23,2,3,1,11,111,11,2,2,2,]
// 结果数组
var result = [];
//遍历数组
for(var i=0;i<arr.length;i++){
//判断遍历的这项是否在结果数组中,如果不在就推入
//includes方法用来判断某项是否在数组中
if(!result.includes(arr[i])){
result.push(arr[i]);
}
}
console.log(result);
var arr = [1,2,3,4,5,[3,6,8]];
//结果数组
var result = [];
// 如果使用 result = arr;则将arr的内存地址传给了result,而数值无法克隆
//遍历原数组的每一项,把遍历到的项推入到结果数组中
for(var i =0 ;i< arr.length;i++){
result.push(arr[i])
}
console.log(result);
console.log(result == arr);//期望false,因为引用类型值进行传递比较的时候,==比较的是内存地址
console.log(result[4] == arr[4]); //藕断丝连
// 冒泡排序
var arr = [1,23,4,5356,3,2,65,5];
//一趟趟 比较,趟数序号就是i
for(var i =1;i < arr.length;i++){
//内层循环负责两两相比较
for(var j = arr.length-1;j>=i;j--){
//判断项的大小
if(a[j]<a[j-1]){
var temp = arr[j];
arr[j] = arr[j-1];
arr [j-1] = temp;
}
}
console.log(arr);
}
console.log(arr);
// 函数中的a、b分别表示数组中靠前和靠后的项,
//如果需要将它们交换位置,则返回任意正数;否则就返回负数。
var arr =[33,55,22,11,66];
//排序
arr.sort(function (a,b){
return a-b;
});
console.log(arr);
//斐波那契数列是这样的数列:1、1、2、3、5、8、13、21
// 编写一个函数,这个函数的功能是返回斐波那契数列中下标为n的那项
function fib(n){
// 数列下标为0的项目,和下标为1的项值都是1
if(n ==0 || n==1) return 1;
//斐波那契数列的本质特征就是每一项,都等于前面两项的和
return fib(n-1) + fib(n-1);
}
// 书写一个循环语句,计算斐波那契数列的前15项
for(var i =0;i<15;i++){
console.log(fib(i));
}
// 题目:刺叭花数是这样的三位数:其每一位数字的阶乘之和恰好等于它本身。即abc=a!+b!+c!,其中abc表示一个三位数。试寻找所有喇叭花数。
// 思路:将计算某个数字的阶乘封装成函数,这样可以让问题简化。
//阶乘函数,计算一个数字的阶乘
function factorial(n){
//累乘器
var result = 1;
for( var i=1 ; i<= n; i++){
result *= i;
}
return result;
}
//穷举法,从100-999寻找喇叭花数
for(var i = 100; i<= 999;i++){
// 把数字i转成字符串
var i_str = i.toString();
// abc分别表示百位\十位\个位
var a = Number(i_str[0]);
var b = Number(i_str[1]);
var c = Number(i_str[2]);
// 根据喇叭花数的条件,来判断
if(factorial(a) + factorial(b) + factorial(c) == i){
console.log(i);
}
}
//使用递归思想,整体思路和浅克隆类似,但稍微进行一些改动:如果遍历到项是基本类型值,则直接推入结果数组;如果遍历到的项是又是数组,则重复执行浅克隆的操作。
//原数组
var arr1 = [33,44,11,22,[66,88]];
//函数,这个函数会被递归
function deepClonw(arr){
// 结果数组,每一层都有一个结果数组
var result = [];
// 遍历数组中的每一项
for(var i=0;i<arr.length;i++){
//类型判断,如果遍历到的项是数组
if(Array.isArray(arr[i])){
// 递归
result.push(deepClonw(arr[i]));
}else {
//如果遍历到的项不是数组,是基本类型值,就直接推入到结果数组中
result.push(arr[i]);
}
}
//返回结果数组
return result;
}
// 测试一下
var arr2 = deepClonw(arr1);
console.log(arr2);
//是否'藕断丝连'
console.log(arr1[4][2] == arr2[4][2]);
arr1[4].push(99);
console.log(arr1);
console.log(arr2);
//题目:请定义一个变量a,要求是能保证这个a只能被进行指定操作(如加1、乘2),而不能进行其他操作,应该怎么编程呢?
//封装一个函数,这个函数的功能就是私有化变量
function fun(){
//定义一个局部变量a
var a= 0;
return{
getA:function (){
return a;
},
add:function (){
a++;
},
pow:function (){
a *=2;
}
};
}
var obj = fun();
// 如果想在fun函数外面使用变量a,唯一的方法就是调用getA()方法
console.log(obj.getA());
// 想让变量a进行+1操作
obj.add();
obj.add();
obj.add();
console.log(obj.getA());
obj.pow();
console.log(obj.getA());
//IIFE:立即执行函数(使语法更紧凑)
// 作用一:为变量赋值 (if语句中)
var age = 12;
var sex = '男'
var title = (function(){
if (age < 18){
return '小朋友'
}else{
if(sex == '男'){
return '先生';
}else{
return '女士';
}
}
})();
alert(title);
//作用二:将全局变量变为局部变量(for语句中)
var arr = [];
for (var i = 0; i<5;i++){
(function (i){
arr.push(function (){
alert(i);
});
})(i);
}
arr[0]();
arr[1]();
arr[2]();
arr[3]();
arr[4]();