Home
  • 计算机网络
  • 操作系统
  • 数据结构与算法
  • 设计模式
  • JavaSE
  • JVM
  • JUC
  • Netty
  • CPP
  • QT
  • UE
  • Go
  • Gin
  • Gorm
  • HTML
  • CSS
  • JavaScript
  • vue2
  • TypeScript
  • vue3
  • react
  • Spring
  • SpringMVC
  • Mybatis
  • SpringBoot
  • SpringSecurity
  • SpringCloud
  • Mysql
  • Redis
  • 消息中间件
  • RPC
  • 分布式锁
  • 分布式事务
  • 个人博客
  • 弹幕视频平台
  • API网关
  • 售票系统
  • 消息推送平台
  • SaaS短链接系统
  • Linux
  • Docker
  • Git
GitHub (opens new window)
Home
  • 计算机网络
  • 操作系统
  • 数据结构与算法
  • 设计模式
  • JavaSE
  • JVM
  • JUC
  • Netty
  • CPP
  • QT
  • UE
  • Go
  • Gin
  • Gorm
  • HTML
  • CSS
  • JavaScript
  • vue2
  • TypeScript
  • vue3
  • react
  • Spring
  • SpringMVC
  • Mybatis
  • SpringBoot
  • SpringSecurity
  • SpringCloud
  • Mysql
  • Redis
  • 消息中间件
  • RPC
  • 分布式锁
  • 分布式事务
  • 个人博客
  • 弹幕视频平台
  • API网关
  • 售票系统
  • 消息推送平台
  • SaaS短链接系统
  • Linux
  • Docker
  • Git
GitHub (opens new window)
  • 变量与数据类型
    • 声明变量
      • let
      • const
      • var
    • 基本类型
      • undefined&null
      • string
      • boolean
    • 对象类型
      • Function
      • Array
      • Object
  • JavaScript
Nreal
2023-12-29
目录

变量与数据类型

# 声明变量

# let

可以被多次赋值

let a = 100;
a = 200;
1
2

# const

只能赋值一次

const b = 100;
b = 200;// error,不能再次赋值
1
2

引用的内容可以修改

const c = [1,2,3];
c[2] = 4;// [1,2,4]
c = [5,6];// error,不能再次赋值
1
2
3

# var

可以被多次赋值

var d = 1;
c = 100;
1
2

# 基本类型

# undefined&null

二者合称 Nullish;

区别:

  • undefined 由 js 产生
  • null 由程序员提供
  • 执行表达式或函数,没有返回结果,出现 undefined;

    console.log(1);  	// 函数没有返回值, 结果是  undefined
    let a = 10;		 	// 表达式没有返回值, 结果是 undefined
    
    1
    2
  • 访问数组不存在的元素,访问对象不存在的属性,出现 undefined;

    let b = [1,2,3];
    console.log(b[10]); // 数组未定义元素是 undefined
    let c = {"name":"张三"};
    console.log(c.age); // 对象未定义属性是 undefined
    
    1
    2
    3
    4
  • 定义变量,没有初始化,出现 undefined;

    let d;
    console.log(d);		// 变量未初始化是 undefined
    
    1
    2

# string

三种写法:

let a = "hello";  // 双引号
let b = 'hello';  // 单引号
let c = `hello`;  // 反引号
1
2
3

模板字符串:

需求:拼接 URI 的请求参数,如

/test?name=zhang&age=18
/test?name=li&age=20
1
2

传统方法拼接

let name = ; // zhang li ...
let age = ; // 18 20 ...

let uri = "/test?name=" + name + "&age=" + age;
1
2
3
4

模板字符串方式

let name = ; // zhang li ...
let age = ; // 18 20 ...

let uri = `/test?name=${name}&age=${age}`;
1
2
3
4

# boolean

  • Falsy

    • false
    • Nullish (null, undefined)
    • 0, 0n, NaN
    • "" '' `` 即长度为零的字符串
  • Truthy

    容易误当作falsy的truthy:

    • "false", "0" 即字符串的 false 和 字符串的零
    • [] 空数组
    • {} 空对象

# 对象类型

# Function

# 函数定义与调用

定义函数:

function 函数名(参数) {
    // 函数体
    return 结果;
}
1
2
3
4

调用函数:

函数名(实参);
1

js对函数参数的类型和个数没有限制:

function add(a, b) {
    return a + b;
}
1
2
3
add('a', 'b');  // 返回 ab
add(4, 5, 6);   // 返回 9, 第三个参数没有被用到, 不会报错
add(1);			// 返回 NaN, 这时 b 没有定义是 undefined, undefined 做数学运算结果就是 NaN
1
2
3

# 默认参数

java 中(spring)要实现默认参数的效果得这么做:

@RestController 
public class MyController {
    
    @RequestMapping("/page")
    @ResponseBody
    public void page(
        @RequestParam(defaultValue="1") int page, 
        @RequestParam(defaultValue="10") int size
    ){
        // ...
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

js

function pagination(page = 1, size = 10) {
    console.log(page, size);
}
1
2
3

# 匿名函数

语法:

(function (参数) {
    // 函数体
    return 结果;
})
1
2
3
4

使用场景:

  1. 定义完立即调用:

    (function(a,b){
        return a + b;
    })(1,2)
    
    1
    2
    3
  2. 作为其它对象的方法:

    页面有元素

    <p id="p1">点我啊</p>
    
    1

    此元素有一个 onclick 方法,会在鼠标单击这个元素后被执行,onclick 方法刚开始是 null,需要赋值后才能使用

    document.getElementById("p1").onclick = (function(){
        console.log("鼠标单击了...");
    });
    
    1
    2
    3

# 箭头函数

(参数) => {
    // 函数体
    return 结果;
}
1
2
3
4
  • 如果没有参数,() 还是要保留;
  • 如果只有一个参数,() 可以省略;
  • 如果函数体内只有一行代码,{} 可以省略;
  • 如果这一行代码就是结果,return 可以省略;

例

document.getElementById("p1").onclick = () =>  console.log("aa");
1

# 函数是对象

  1. 可以参与赋值:

    function abc() {
        console.log("bb");
    }
    
    document.getElementById("p1").onclick = abc;
    
    1
    2
    3
    4
    5
  2. 有属性、有方法,执行 console.dir(abc),输出结果如下:

    ƒ abc()
        arguments: null
        caller: null
        length: 0
        name: "abc"
        ➡prototype: {constructor: ƒ}
        [[FunctionLocation]]: VM1962:1
        ➡[[Prototype]]: ƒ ()
        ➡[[Scopes]]: Scopes[1]
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
  3. 可以作为方法参数:

    function a() {
        console.log('a')
    }
    
    function b(fn) {          // fn 将来可以是一个函数对象
        console.log('b')
        fn();                 // 调用函数对象
    }
    
    b(a)
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
  4. 可以作为方法返回值:

    function c() {
        console.log("c");
        function d() {
            console.log("d");
        }
        return d;
    }
    
    c()()
    
    1
    2
    3
    4
    5
    6
    7
    8
    9

# 函数作用域

function c() {
    var z = 30;
}

var x = 10;
function a() {
    var y = 20;
    function b() {
        // 看这里
        console.log(x, y);
    }
    b();
}
a();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  • 以函数为分界线划定作用域,所有函数之外是全局作用域;
  • 查找变量时,由内向外查找
    • 在内层作用域找到变量,就会停止查找,不会再找外层;
    • 所有作用域都找不到变量,报错;
  • 作用域本质上是函数对象的属性,可以通过 console.dir 来查看调试;

# 闭包

闭包就是指函数能够访问自己的作用域中变量;

函数定义时,它的作用域已经确定好了,因此无论函数将来去了哪,都能从它的作用域中找到当时那些变量;

var x = 10;
function a() {
    var y = 20;
    function b() {
        console.log(x,y);
    }
    return b;
}
a()();  // 在外面执行了 b
1
2
3
4
5
6
7
8
9

Java中类似于闭包(Lambda表达式参数捕获):

主方法中也能返回a方法的局部变量;

public static void main(String[] args){
    a().accept(10);
}
public static Consumer<Integer> a(){
    int y = 20;
    Consumer<Integer> b = 
        x->sout(x+ " "+ y);
    return b;
}
1
2
3
4
5
6
7
8
9

# let、var与作用域

如果函数外层引用的是 let 变量,那么外层普通的 {} 也会作为作用域边界,最外层的 let 也占一个 script 作用域;

let x = 10; 
if(true) {
    let y = 20;
    function b() {
        console.log(x,y);
    }
    console.dir(b);
}
1
2
3
4
5
6
7
8

如果函数外层引用的是 var 变量,外层普通的 {} 不会视为边界;

var x = 10; 
if(true) {
    var y = 20;
    function b() {
        console.log(x,y);
    }
    console.dir(b);
}
1
2
3
4
5
6
7
8

如果 var 变量出现了重名,则他俩会被视为同一作用域中的同一个变量;

var e = 10; 
if(true) {
    var e = 20;
    console.log(e);	// 打印 20
}
console.log(e);		// 因为是同一个变量,还是打印 20
1
2
3
4
5
6

如果是 let,则视为两个作用域中的两个变量;

let e = 10; 
if(true) {
    let e = 20;	
    console.log(e);	// 打印 20
}
console.log(e);		// 打印 10
1
2
3
4
5
6

要想里面的 e 和外面的 e 能区分开来,最简单的办法是改成 let,或者用函数来界定作用域范围

var e = 10; 
if(true) {
    function b() {
        var e = 20;
    	console.log(e);
    }
    b();
}
console.log(e);	
1
2
3
4
5
6
7
8
9

# Array

语法

// 创建数组
let arr = [1,2,3]; 

// 获取数组元素
console.log(arr[0]); // 输出 1

// 修改数组元素
array[0] = 5;		 // 数组元素变成了 [5,2,3]

// 遍历数组元素,其中 length 是数组属性,代表数组长度
for(let i = 0; i < arr.length; i++) {
    console.log(arr[i]);
}
1
2
3
4
5
6
7
8
9
10
11
12
13

API

  • push、shift、splice
let arr = [1,2,3]; 

arr.push(4);    	// 向数组尾部(右侧)添加元素, 结果 [1,2,3,4]
arr.shift();		// 从数组头部(左侧)移除元素, 结果 [2,3,4]
arr.splice(1,1);	// 删除【参数1】索引位置的【参数2】个元素,结果 [2,4]
1
2
3
4
5
  • join
let arr = ['a','b','c'];

arr.join(); 		// 默认使用【,】作为连接符,结果 'a,b,c'
arr.join('');		// 结果 'abc'
arr.join('-');		// 结果 'a-b-c'
1
2
3
4
5
  • map、filter、forEach

    两个称呼

    • 高阶函数,map,filter,forEach
    • 回调函数,例如作为参数传入的函数

map 例子:

传给 map 的函数,参数代表旧元素,返回值代表新元素

let arr = [1,2,3,6];

function a(i) {   // 代表的新旧元素之间的变换规则
    return i * 10
}

// arr.map(a) // 具名函数,结果 [10,20,30,60]

// arr.map( (i) => {return i * 10} ); // 箭头函数
arr.map( i => i * 10 ); // 箭头函数
1
2
3
4
5
6
7
8
9
10

filter 例子:

传给 filter 的函数,参数代表旧元素,返回 true 表示要留下的元素

let arr = [1,2,3,6];
arr.filter( (i)=> i % 2 == 1 ); // 结果 [1,3]
1
2

forEach 例子:

let arr = [1,2,3,6];

/*for(let i = 0; i < arr.length; i++) {
    console.log(arr[i]);
}*/

arr.forEach( (i) => console.log(i) );
1
2
3
4
5
6
7

# Object

# 语法

let obj = {
    属性名: 值,
    方法名: 函数,
    get 属性名() {},
    set 属性名(新值) {}
}
1
2
3
4
5
6
  1. 例一:

    let stu1 = {
        name: "小明",
        age: 18,
        study: function(){
            console.log(this.name + "爱学习");
        }    
    }
    
    1
    2
    3
    4
    5
    6
    7
  2. 例二:

    let name = "小黑";
    let age = 20;
    let study = function(){
        console.log(this.name + "爱学习");
    }
    
    let stu2 = { name, age, study }
    
    1
    2
    3
    4
    5
    6
    7
  3. 例三:

    let stu3 = {
        name: "小白",
        age: 18,
        study(){
            console.log(this.name + "爱学习");
        }    
    }
    
    1
    2
    3
    4
    5
    6
    7
  4. 例四:

    let stu4 = {
        _name: null, /*类似于java中私有成员变量*/
        get name() {
            console.log("进入了get");
            return this._name;
        },
        set name(name) {
            console.log("进入了set");
            this._name = name;
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    调用get,set:

    stu4.name = "小白"
    
    console.log(stu4.name)
    
    1
    2
    3

# 属性增删

let stu = {name:'张三'};
stu.age = 18;					// 添加属性
delete stu.age;					// 删除属性

stu.study = function() {		// 添加方法
    console.log(this.name + "在学习");
}
1
2
3
4
5
6
7

添加 get,set,需要借助 Object.definePropery

let stu = {_name:null};

Object.defineProperty(stu, "name", {
    get(){
        return this._name;
    },
    set(name){
        this._name = name;
    }
});
1
2
3
4
5
6
7
8
9
10
  • 参数1:目标对象
  • 参数2:属性名
  • 参数3:get,set 的定义

# this

Java中this:隐式参数

public class TestMethod {

    static class Student {
        private String name;

        public Student(String name) {
            this.name = name;
        }

        public void study(Student this, String subject) {
            System.out.println(this.name + "在学习 " + subject);
        }
    }

    public static void main(String[] args) {
        Student stu = new Student("小明");
        
        // 下面的代码,本质上是执行 study(stu, "java"),因此 this 就是 stu
        stu.study("java"); 
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

js 中的 this 也是隐式参数,但它与函数运行时上下文相关:

  1. "落单"函数;

    function study(subject) {
        console.log(this.name + "在学习 " + subject)
    }
    
    1
    2
    3

    测试:

    study("js");  // 输出 在学习 js
    
    1

    函数执行,全局对象 window 被当作了 this,window 对象的 name 属性是空串;

  2. 同样函数作为对象方法:

    let stu = {
        name:"小白",
        study
    }
    
    1
    2
    3
    4

    测试:

    stu.study('js'); 	// 输出 小白在学习 js
    
    1
  3. 动态改变this:

    call 的第一个参数 stu 作为 this;

    let stu = {name:"小黑"};
    study.call(stu, "js");	// 输出 小黑在学习 js
    
    1
    2
  4. 箭头函数中this:

    以外层this理解;

    1. 当用匿名函数,this.name是落单函数,this代表window;

      let stu = {
          name: "小花",
          friends: ["小白","小黑","小明"],
          play() {
              this.friends.forEach(function(e){
                  console.log(this.name + "与" + e + "在玩耍");
              });
          }
      }
      stu.play()
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      与小白在玩耍
      与小黑在玩耍
      与小明在玩耍
      
      1
      2
      3
    2. 当用箭头函数,this 要看它外层的 play 函数,play 又是属于 stu 的方法,因此 this 代表 stu 对象;

      let stu = {
          name: "小花",
          friends: ["小白","小黑","小明"],
          play() {
              this.friends.forEach(e => {
                  console.log(this.name + "与" + e + "在玩耍");
              })
          }    
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      小花与小白在玩耍
      小花与小黑在玩耍
      小花与小明在玩耍
      
      1
      2
      3
    3. 若不用箭头函数:

      let stu = {
          name: "小花",
          friends: ["小白","小黑","小明"],
          play() {
              let me = this;
              this.friends.forEach(function(e){
                  console.log(me.name + "与" + e + "在玩耍");
              });
          }
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10

# 原型继承

let father = {
    f1: '父属性',
    m1: function() {
        console.log("父方法");
    }
}

let son = Object.create(father);

console.log(son.f1);  // 打印 父属性
son.m1();			  // 打印 父方法
1
2
3
4
5
6
7
8
9
10
11
  • father 是父对象,son 去调用 .m1 或 .f1 时,自身对象没有,就到父对象找;
  • son 自己可以添加自己的属性和方法;
  • son 里有特殊属性 __proto__ 代表它的父对象,js 术语: son 的原型对象;

基于函数的原型继承:

Theme by Vdoing | Copyright © 2021-2024
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式