数组,函数,作用域,对象)
keyipatience:个人主页作者简介C/C后端开发学习者专栏传送门《c》《linux》《c高阶数据结构》《c数据结构与算法》《前端学习》⭐️patience is key in life数组1.创建数组两种写法1new Array()了解即可不常用let arr new Array(); // Array首字母必须大写2字面量 []推荐、常用let arr []; // 空数组 let arr2 [1, 2, haha, false];JS 数组元素可以是不同类型数字、字符串、布尔混放都行C/Java 数组要求类型统一。2. 获取 / 修改数组元素下标索引let arr [小猪佩奇, 小猪乔治, 小羊苏西]; console.log(arr[0]); // 小猪佩奇 console.log(arr[1]); // 小猪乔治 console.log(arr[2]); // 小羊苏西 arr[2] 小猫凯迪; // 修改下标2的元素下标越界不存在的下标读取 → undefinedconsole.log(arr[3]); // undefined console.log(arr[-1]);// undefined不要直接给数组变量名重新赋值let arr [小猪佩奇, 小猪乔治, 小羊苏西]; arr 小猫凯迪; // 原本arr是数组现在arr直接变成字符串数组全部丢失3. 新增元素方式修改 length 新增把数组 length 改大数组末尾自动增加空位新增元素默认值undefinedvar arr [10,20]; arr.length 3; console.log(arr[2]); // undefined通过下标新增元素如果下标超出当前数组范围直接赋值会在指定下标添加元素中间空出来的位置自动填充为undefinedlet arr []; arr[2] 10; console.log(arr); // [undefined, undefined, 10] 解释 - 给下标 2 赋值数组长度自动变成 3 - arr[0] arr[1]没有赋值默认是 undefinedpush () 在数组末尾追加元素示例代码筛选奇数let arr [9, 5, 2, 7, 3, 6, 8]; let newArr []; for (var i 0; i arr.length; i) { if (arr[i] % 2 ! 0) { // 判断是否是奇数除以2余数不等于0 newArr.push(arr[i]); } } console.log(newArr); // [9,5,7,3]删除数组元素splice ()语法arr.splice(起始下标, 删除个数)let arr [9, 5, 2, 7]; arr.splice(2, 1); // 从下标2开始删除1个元素 console.log(arr); // [9,5,7]JS 函数1.基本语法// 函数定义声明 function 函数名(形参列表) { 函数体 return 返回值; } // 函数调用 函数名(实参列表); // 不接收返回值 let res 函数名(实参列表); // 接收返回值重点定义函数不会执行代码只有调用才执行调用几次执行几次egfunction hello() { console.log(hello); } hello(); // 调用才会打印hello函数声明特点函数提升可以先调用、后定义普通变量不行hello(); // 先调用 function hello() { console.log(hello); }2.形参、实参个数不匹配实参 形参多传的实参函数里面不参与运算直接忽略function sum(a,b){ return ab; } sum(10,20,30); // 结果3030这个实参没用实参 形参没传值的形参 undefined计算容易得到NaNsum(10); // a10bundefined10undefined → NaN3.函数表达式匿名函数赋值给变量和lamda表达式相似function(){}没有名字 →匿名函数把匿名函数存到变量通过变量名调用arguments函数内部自带伪数组保存本次调用全部实参适合参数数量不确定场景let add function() { let sum 0; // arguments内置伪数组拿到调用时所有传入实参 for(let i 0; i arguments.length; i){ sum arguments[i]; } return sum; } add(10,20); add(1,2,3,4);JS 作用域1. 全局作用域写在函数外面整个 script 标签 /js 文件都能用var直接在最外层定义 →全局变量let num 10; // 全局变量 function test() { } console.log(num); // 内外都可以访问2. 局部作用域函数作用域在函数内部用 var 定义的变量只能在当前函数里面访问函数外面访问不到这个局部变量同名变量局部优先就近原则函数内优先使用自己内部的变量屏蔽全局let num 10; //全局 function test2() { let num 30; //局部覆盖全局 console.log(num); //打印30 }3. 坑不写 var 直接赋值 → 自动变成全局变量严禁这么写function test() { num 100; // 没有var不是局部变量直接创建全局变量 } test(); console.log(num); // 100外面能读到作用域链查找顺序先在当前内层函数作用域找变量找不到 → 去外层包裹函数的作用域查找还找不到 → 去全局作用域查找全局也找不到 → 报错is not defined由内向外就近优先找到立刻停止let num 1; // 全局 function test1() { let num 10; function test2() { let num 20; console.log(num); // 先在test2里面找到num20直接用 } test2(); } test1(); //输出20JS对象对象一个具体的事物类别类 /class泛指一类东西比如 “电脑”是模板、抽象概念对象类的具体实例“我的联想笔记本”两个组成部分属性事物的特征描述信息名词 例身高、体重、姓名方法事物的行为可以做的动作函数 例唱歌、跳舞JS 里字符串、数字、数组、函数全都是对象JS 对象 vs Java 对象概念思想一样类是模板对象是实例包含属性 方法只是语法写法不一样Java用 class严格类型JS早期可以直接字面量{}创建对象ES6 后也支持 class 语法JS 两种创建对象方式1. 对象字面量{}最常用 let student { name: 小明, height: 175, weight: 170, sayHello: function () { console.log(hello); } };规则大括号{}键值键值对存放属性、方法键和值之间用:键值对之间用,分隔访问属性两种写法// 点语法 . 最常用 console.log(student.name); // 方括号 []属性名要加引号 console.log(student[height]); // 调用方法一定要加() student.sayHello();2.new Object()创建对象let student new Object(); // 空对象 let student {};//也可以 student.name 小明; student.height 175; student[weight] 170; student.sayHello function () { console.log(hello); }思路先新建空对象再一个个追加属性和方法。3.构造函数创建对象基础语法模板function 构造函数名(形参) { this.属性 值; this.方法 function() { // ... } } let obj new 构造函数名(实参);eg:function People(name, height, weight) { this.name name this.height height this.weight weight this.Say function() { console.log(name say hello) } } let xiaoming new People(小明, 175, 75) let zhangsan new People(张三, 175, 75) console.log(xiaoming) xiaoming.Say() console.log(zhangsan) zhangsan.Say() //输出结果 People { name: 小明, height: 175, weight: 75, Say: [Function: Say] } 小明say hello People { name: 张三, height: 175, weight: 75, Say: [Function: Say] } 小明say hello注意事项规范构造函数名首字母大写约定用来区分普通函数每new Cat()一次就会生成一个新对象每个对象身上都会新建一份 func 函数缺点耗内存相当于给当前实例对象新增一个属性所以要有this指针不是方法。对比后面的class解决办法把方法放到原型 prototype 上People.prototype.Say function(){ console.log(this.sound) }所有 Cat 实例共用同一个 miao 函数节省内存理解 new 关键字new Cat(...)做了这几件事在内存创建一个空 {} 对象把函数内的 this 指向这个空对象执行构造函数代码给 this 挂载属性、方法自动 return 这个对象总结方式适用场景特点字面量{}只创建单个对象简单一次性写死new Object()单个对象后期追加属性很少用构造函数 function Cat批量多个同类对象复用模板快速 new 多个实例4.class构建对象在ES6后我们就还可以通过class构造创建对象class People { constructor(name, height, weight) { this.name name this.height height this.weight weight } Say() { console.log(this.name 正在说hello) } } let xiaoming new People(小明, 175, 75) console.log(xiaoming) xiaoming.Say() //运行输出 People { name: 小明, height: 175, weight: 75 } 小明正在说hello注意事项名字固定只能叫 constructor不能改名一个类最多只能有 1 个 constructor写多个直接报错方法miao写在 class 大括号里自动放到原型 prototype 上好处所有实例共用同一个 miao 函数不会像旧构造函数那样每次 new 都新建函数节省内存class 中的 staticstatic 用来定义属于【类本身】的属性 / 方法不属于 new 出来的实例对象。静态方法 / 静态属性直接用类名访问不能用实例访问class People{ static hello(){ console.log(静态方法) } } People.hello(); // ✅ 正确 let p new People(); p.hello(); // ❌ 报错实例访问不到staticclass 继承extends让子类继承父类的属性、方法super()调用父类的构造方法// 父类 class People { constructor(name, height) { this.name name; this.height height; } Say() { console.log(this.name 正在说); } } // Student 子类继承 People父类 class Student extends People { // 子类构造方法 constructor(name, height, id) { // ✅ 必须第一行写super调用父类constructor super(name, height); this.id id; // 子类自己新增的属性 } // 重写Say Say(){ super.Say(); // 执行父类Say输出小明正在说 console.log(学生this.namethis.id在说话); } } let s new Student(小明,175,2026001); s.Say();//输出:学生小明2026001在说话class 子类 extends 父类开启继承子类写了 constructor第一句必须super(参数)用来执行父类构造、继承父类属性没写 super 就不能用this子类可以重写同名方法优先执行子类自己的方法覆盖父类子类方法内部super.Say()可以调用父类原来的 Say