JS学习笔记(2)数组,函数,作用域,对象

🔥keyipatience:个人主页

🎬作者简介:C/C++后端开发学习者

🌟专栏传送门:《c++》《linux》《c++高阶数据结构》《c++数据结构与算法》《前端学习》

⭐️patience is key in life

数组

1.创建数组两种写法

1)new 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的元素

下标越界(不存在的下标)读取 → undefined

复制代码
console.log(arr[3]); // undefined
console.log(arr[-1]);// undefined

不要直接给数组变量名重新赋值

复制代码
let arr = ['小猪佩奇', '小猪乔治', '小羊苏西'];
arr = '小猫凯迪'; 
// 原本arr是数组,现在arr直接变成字符串!数组全部丢失!

3. 新增元素方式

修改 length 新增

把数组 length 改大,数组末尾自动增加空位,新增元素默认值 undefined

复制代码
var arr = [10,20];
arr.length = 3;
console.log(arr[2]); // undefined

通过下标新增元素

如果下标超出当前数组范围直接赋值 ,会在指定下标添加元素,中间空出来的位置自动填充为 undefined

复制代码
let arr = [];
arr[2] = 10; 
console.log(arr); // [undefined, undefined, 10]


解释:

- 给下标 2 赋值,数组长度自动变成 3
- `arr[0] arr[1]没有赋值,默认是 undefined

push () 在数组末尾追加元素

示例代码(筛选奇数):

复制代码
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 = 函数名(实参列表);     // 接收返回值

重点:定义函数不会执行代码,只有调用才执行;调用几次执行几次

eg:

复制代码
function hello() {
  console.log("hello");
}
hello(); // 调用,才会打印hello

函数声明特点:函数提升,可以先调用、后定义(普通变量不行)

复制代码
hello(); // 先调用
function hello() {
  console.log("hello");
}

2.形参、实参个数不匹配

实参 > 形参:多传的实参,函数里面不参与运算,直接忽略

复制代码
function sum(a,b){
  return a+b;
}
sum(10,20,30); // 结果30,30这个实参没用

实参 < 形参 :没传值的形参 = undefined,计算容易得到 NaN

复制代码
sum(10); // a=10,b=undefined;10+undefined → NaN

3.函数表达式(匿名函数赋值给变量)

和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,外面能读到

作用域链

查找顺序:

  1. 先在当前内层函数作用域找变量
  2. 找不到 → 去外层包裹函数的作用域查找
  3. 还找不到 → 去全局作用域查找
  4. 全局也找不到 → 报错:is not defined

由内向外,就近优先;找到立刻停止

复制代码
let num = 1; // 全局
function test1() {
  let num = 10;
  function test2() {
    let num = 20;
    console.log(num); // 先在test2里面找到num=20,直接用
  }
  test2();
}
test1();
//输出:20

JS对象

对象:一个具体的事物

  • 类别(类 /class):泛指一类东西(比如 "电脑"),是模板、抽象概念
  • 对象:类的具体实例("我的联想笔记本")

两个组成部分

  1. 属性 :事物的特征(描述信息,名词) 例:身高、体重、姓名
  2. 方法 :事物的行为(可以做的动作,函数) 例:唱歌、跳舞

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

注意事项

  1. 规范:构造函数名首字母大写(约定,用来区分普通函数)
  2. 每new Cat()一次,就会生成一个新对象,每个对象身上都会新建一份 func 函数 (缺点!耗内存)相当于给当前实例对象新增一个属性(所以要有this指针),不是方法。对比后面的class

解决办法:把方法放到原型 prototype 上

复制代码
People.prototype.Say = function(){
  console.log(this.sound)
}

所有 Cat 实例共用同一个 miao 函数,节省内存!

理解 new 关键字

new Cat(...) 做了这几件事:

  1. 在内存创建一个空 {} 对象
  2. 把函数内的 this 指向这个空对象
  3. 执行构造函数代码,给 this 挂载属性、方法
  4. 自动 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

注意事项:

  1. 名字固定,只能叫 constructor,不能改名!
  2. 一个类最多只能有 1 个 constructor,写多个直接报错
  3. 方法(miao)写在 class 大括号里,自动放到原型 prototype 上

好处:所有实例共用同一个 miao 函数,不会像旧构造函数那样,每次 new 都新建函数,节省内存

class 中的 static

static 用来定义属于【类本身】的属性 / 方法,不属于 new 出来的实例对象。 静态方法 / 静态属性,直接用类名访问,不能用实例访问

复制代码
class People{
  static hello(){
    console.log("静态方法")
  }
}
People.hello(); // ✅ 正确
let p = new People();
p.hello(); // ❌ 报错!实例访问不到static

class 继承

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.name+this.id+"在说话");
  }
}

let s = new Student("小明",175,2026001);
s.Say();//输出:学生小明2026001在说话
  1. class 子类 extends 父类 开启继承
  2. 子类写了 constructor,第一句必须 super(参数) ,用来执行父类构造、继承父类属性;没写 super 就不能用this
  3. 子类可以重写同名方法,优先执行子类自己的方法(覆盖父类)
  4. 子类方法内部,super.Say() 可以调用父类原来的 Say
相关推荐
2603_965148113 小时前
商品价格监控 API 接口:从原理到实战的完整指南
java·前端·数据库·python·生活
donk13143 小时前
React Native for OpenHarmony 实战:三方库 react-native-segmented-control-tab 的鸿蒙化适配指南
javascript·react native·react.js·华为·harmonyos
酷虎软件3 小时前
视频加字幕怎么制作
java·前端·音视频
你想知道什么?3 小时前
词向量总结-学习笔记
人工智能·笔记·学习
He BianGu3 小时前
【笔记】WPF中RenderOptions类的详细功能
笔记·wpf
Geoffwo3 小时前
robotjs0.6.0鼠标中轴滚动失效修复方案
前端·javascript
用AI来创业吧3 小时前
网站建设公司哪家好:报价差 3 倍,差在哪四项成本上(选型笔记)
笔记·性能优化·软件工程·安全威胁分析
彭亚川Allen3 小时前
从零手搓 RAG 之文档解析技术
前端·后端·架构
yangmu32033 小时前
开发网站的完整流程:从0到1上线指南
运维·学习