笔记来源尚硅谷最新版JavaScript基础全套教程完整版(140集实战教学,JS从入门到精通)_哔哩哔哩_bilibili

作用域

作用域指一个变量的作用的范围

在JS中一共有两种作用域:

  • 全局作用域
  • 函数作用域

1、全局作用域

直接编写在script标签中的JS代码,都在全局作用域

全局作用域在页面打开时创建,在页面关闭时销毁

在全局作用域中有一个全局对象window,它代表的是一个浏览器的窗口,由浏览器创建,可以直接使用

在全局作用域中:

  • 创建的变量都会作为window对象的属性保存
  • 创建的函数都会作为window对象的方法保存

全局作用域中的变量都是全局变量,在页面的任意的部分都可以访问的到

  1. var a = 3;
  2. console.log(window.a); //3
  3. console.log(a); //3
  4. b = 3;
  5. console.log(b); //3

1.1、变量的声明提前

使用var关键字声明的变量,会在所有的代码执行之前被声明

但是如果声明变量时不适用var关键字,则变量不会被声明提前

  1. // 1、变量的声明提前
  2. console.log("a = " + a); // a = undefined
  3. var a = "abc";
  4. // ======相当于======
  5. var a;
  6. console.log("a = " + a); // a = undefined
  7. a = "abc";
  8. // 2、没有变量的声明提前,报错
  9. console.log("b = " + b); // UncaughtReferenceError: b is not defined
  10. b = "abc";
  11. // ======相当于======
  12. console.log("b = " + b); // UncaughtReferenceError: b is not defined
  13. window.b = "abc";

1.2、函数的声明提前

使用函数声明形式创建的函数function

  1. 函数(){
  2. 语句...
  3. }

它会在所有的代码执行之前就被创建,所以我们可以在函数声明前来调用函数

  1. fun1(); // fun1...
  2. fun2(); // UncaughtTypeError: fun2 is not a function
  3. // 函数声明,会被提前创建
  4. function fun1(){
  5. console.log("fun1...");
  6. }
  7. // 函数表达式,不会被提前创建(变量会被提前声明,但函数不会被提前创建)
  8. var fun2 = function(){
  9. console.log("fun2...");
  10. }

2、函数作用域

调用函数时创建函数作用域,函数执行完毕以后,函数作用域销毁

每调用一次函数就会创建一个新的函数作用域,他们之间是互相独立的

  • 在函数作用域中可以访问到全局作用域的变量
  • 在全局作用域中无法访问到函数作用域的变量

当在函数作用域操作一个变量时,它会先在自身作用域中寻找,

  • 如果有就直接使用
  • 如果没有则向上一级作用域中寻找,直到找到全局作用域
  • 如果全局作用域中依然没有找到,则会报错

在函数中要访问全局变量可以使用window对象

  1. var a = 10;
  2. function fun2(){
  3. var a = 20;
  4. function fun3(){
  5. var a = 30;
  6. console.log("fun3 ==> a = " + a); // fun3 ==> a = 30
  7. }
  8. fun3();
  9. console.log("fun2 ==>a = " + a); // fun2 ==>a = 20
  10. console.log("a = " + window.a); // a = 10
  11. }
  12. fun2();
  13. console.log("a = " + a); // a = 10

在函数作用域也有声明提前的特性,使用var关键字声明的变量,会在函数中所有的代码执行之前被声明

函数声明也会在函数中所有的代码执行之前执行

// 在函数作用域也有声明提前的特性,使用`var`关键字声明的变量,会在函数中所有的代码执行之前被声明
function func1(){
    console.log(a);
    var a = "func1";

    // 函数声明也会在函数中所有的代码执行之前执行
    func2(); // fun2...
    function func2(){
        console.log("fun2...");
    }
}
func1(); // undefined

在函数中,不适用var声明的变量都会成为全局变量

// 函数声明且调用
func3();
function func3() {
    a = 4;
}
console.log("a = " + window.a);  // a = 4
console.log("a = " + window["a"]);   // a = 4
console.log("a = " + a);    // a = 4
// 函数声明不调用
function func4() {
    b = 4;
}
console.log("b = " + window.b);  // b = 4
console.log("b = " + window["b"]);   // b = 4
console.log("b = " + b);    // UncaughtReferenceError: b is not defined

定义形参就相当于在函数作用域中声明了变量

var e = 10;
function fun5(e){
    console.log(e);
}
fun5(); // undefined
fun5(55);  // 55

练习

// 说出以下代码的执行结果
var a = 123; 
function fun(){
    console.log(a);
}
fun();             // 123
// =====================
var a = 123; 
function fun(){
    console.log(a);
    var a = 456;
}
fun();             // undefined
console.log(a);  // 123
// =====================
var a = 123; 
function fun(){
    console.log(a);
    a = 456;
}
fun();             // 123
console.log(a);  // 456
// =====================
var a = 123; 
function fun(a){
    console.log(a);
    a = 456;
}
fun();            // undefined
console.log(a);  // 123
// =====================
var a = 123; 
function fun(a){
    console.log(a);
    a = 456;
}
fun(789);        // 789
console.log(a);  // 123

3、this

解析器在调用函数每次都会向函数内部传递进一个隐含的参数,这个隐含的参数就是this

this指向的是一个对象,这个对象我们称为函数执行的上下文对象

根据函数的调用方式的不同,this会指向不同的对象

  • 以函数的形式调用时,this永远都是window
  • 以方法的形式调用时,this就是调用方法的那个对象
// - 以函数的形式调用时,`this`永远都是`window`
function fun(){
    console.log(this.name);
}
var name = "ddd"; // ddd
fun();
// - 以方法的形式调用时,`this`就是调用方法的那个对象
var obj = {
    name: "孙悟空",
    sayName: fun
}
obj.sayName(); // 孙悟空