声明

  • var变量声明,通俗来说会将变量上升到上级代码块的变量范围中。这里的上级代码块详细来说应该是当前函数作用域或者全局作用域,因为在 JavaScript 里,只有函数全局作用域能够限制var变量的作用域,像if语句、for循环、while循环等代码块是无法限制的。
    比如:
    无法限制var作用域的情况:

    1
    2
    3
    4
    if(true){
    var x = 5;
    }
    console.log(x);//x的值为5

    可以限制var作用域的情况:

    1
    2
    3
    4
    5
    6
    7
    8
    function example() {
    if (true) {
    var x = 5; // 实际上会被提升到函数顶部
    }
    console.log(x); // 可以访问 x,输出 5
    }

    console.log(x); // 报错:ReferenceError(x 不在全局作用域,因为function将其限制)

函数

函数定义与声明

二者区别

函数声明(Function Declaration)

1
2
3
function add(a, b) {
return a + b;
}
  • 特点

    • function关键字开头,后跟函数名。
    • 函数提升(Hoisting):可以在定义前调用(JavaScript 引擎会将函数声明提升到当前作用域的顶部)。
    • 独立语句:不能嵌套在非代码块中(如if语句、赋值语句)。
  • 示例

    1
    2
    3
    4
    console.log(add(2, 3)); // ✅ 可以在定义前调用
    function add(a, b) {
    return a + b;
    }

2. 函数表达式(Function Expression)

1
2
3
const add = function(a, b) {
return a + b;
};
  • 特点

    • function关键字开头(匿名函数),或使用具名函数表达式(如function add(a, b))。
    • 赋值给变量:函数是一个值,存储在变量add中。
    • 没有函数提升:必须在定义后调用(变量提升但值为undefined)。
  • 示例

    1
    2
    3
    4
    console.log(add(2, 3)); // ❌ 报错:add is not a function
    const add = function(a, b) {
    return a + b;
    };

3. 箭头函数(Arrow Function)

1
const add = (a, b) => a + b;
  • 特点

    • 更简洁的语法:使用=>符号,省略function关键字。
    • 隐式返回:单行表达式无需return关键字(如(a, b) => a + b)。
    • 没有自己的this:继承自父作用域(适合回调函数)。
    • 不能使用arguments对象:不绑定arguments变量。
  • 示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // 完整语法
    const add = (a, b) => {
    return a + b;
    };

    // 隐式返回
    const double = num => num * 2;

    // 无参数
    const greet = () => "Hello!";

箭头函数是函数表达式的一种吗?

是的!

JS原型链

Object.create的作用

  • 简单来说,该函数就是为了使一个原型对象继承自另一个原型对象,并且仅仅止步于继承另一个原型对象,它本身的修改不会对原型对象进行影响,比如:

    1
    Child.prototype() = Parent.prototype()

    此时, ChildParent 将共享同一个原型对象。修改 Child.prototype 会直接影响 Parent.prototype,反之亦然。
    所以我们可以使用:

    1
    Child.prototype() = Object.create(Parent.prototype)

    此时Child继承Parent的方法属性,但是后续对Child进行修改也不会影响Parent本身自带的属性

Parent.call(this, name) 的作用

call() 的基本语法

call() 是所有函数都有的方法,用于显式指定函数执行时的 this 值。语法:

1
functionName.call(thisArg, arg1, arg2, ...);
  • thisArg:函数执行时 this 指向的对象
  • arg1, arg2:传递给函数的参数

2. 在继承中的作用:属性继承

在构造函数模式中,Parent.call(this, name) 的作用是:

  1. Child 实例的上下文中执行 Parent 构造函数
  2. Parent 构造函数中的 this 指向 Child 实例
  3. 从而将 Parent 的属性添加到 Child 实例上

示例解析

1
2
3
4
5
6
7
8
function Parent(name) {
this.name = name; // 这里的 this 会指向 Child 实例
}

function Child(name, age) {
Parent.call(this, name); // 相当于在 Child 实例上执行: this.name = name;
this.age = age;
}

执行 new Child("Alice", 18) 时:

  1. 创建一个新的 Child 实例
  2. Parent.call(this, "Alice") 在该实例上添加 name 属性
  3. 接着 this.age = 18 添加 age 属性
1
2
3
const c = new Child("Alice", 18);
console.log(c.name); // Alice(继承自 Parent)
console.log(c.age); // 18(Child 自有属性)

**简单来说:**就是对某个实例对象的方法进行调用,但是整体不会继承该实例对象,其他的属性不会得到继承。

constructor 属性的作用

什么是 constructor

每个对象都有一个 constructor 属性,它指向创建该对象的构造函数。默认情况下,JavaScript 会为原型对象自动添加这个属性。

例如:

1
2
3
function Parent() {}
const p = new Parent();
console.log(p.constructor === Parent); // true

为什么需要手动修正 Child.prototype.constructor

当你使用 Object.create() 设置原型时,会切断默认的 constructor 关联:

1
2
Child.prototype = Object.create(Parent.prototype);
console.log(Child.prototype.constructor); // Parent(错误!)

这是因为 Object.create(Parent.prototype) 创建的新对象继承了 Parent.prototypeconstructor 属性(即 Parent)。

手动修正的目的

1
2
Child.prototype.constructor = Child;
console.log(Child.prototype.constructor); // Child(正确!)

这样做确保:

  • new Child().constructor === Child
  • 保持语言的一致性(虽然这更多是语义上的修复,对功能影响不大

附加小结

  • prototype,即原型链属性,在js中主要与,函数,对象,类有关。或者说,它在这三个类型的数据上适用。