变量作用域

// 声明全局变量 - 全局作用域
var msg = 100;
// 声明局部变量 - 某个函数作用域
function fn() {
  // 局部变量 - 只能在当前函数作用域中访问
  var msg2 = 200;
  console.log(msg2,msg);
}
fn()
console.log(msg)

变量提升

// 先调用后声明
console.log(msg); //打印undefined
var msg = 100;
console.log(msg); //打印100

以上代码会先输出undefined然后输出100 。约等于以下写法

var msg;
console.log(msg);
msg=100;
console.log(msg);

所以变量提升也就是变量的声明被提升

即使我们在定义这个函数之前调用它,函数仍然可以工作。这是因为在 JavaScript 中执行上下文的工作方式造成的。

JavaScript 仅提升声明,而不提升初始化。如果你先使用的变量,再声明并初始化它,变量的值将是 undefined。变量提升也会在函数内产生,例如

var msg = 100;
function fn() {
  console.log(msg); //undefined
  var msg = 200;
  console.log(msg); //200
}
fn();
console.log(msg); // 100

因此我们可以得到结论:全局变量与局部变量同名时,在函数作用域中只能访问局部变量

函数提升

函数提升与变量提升较为类似。函数声明时 函数可以被正确被调用

fn(); //输出 this is function
function fn() {
  console.log("this is function");
}
fn(); // 输出 this is function

如果表达式方式声明存在的函数提升是按照变量提升,因此函数不能被正确调用。

fn(); 
var fn = function () {
  console.log("this is function");
};
fn();
// 报错:TypeError: fn is not a function

变量与函数同名

函数声明方式时 函数提升比变量提升的优先级更高。

console.log(fn); //打印函数fn:[Function: fn]
var fn = 100;
function fn() {
  console.log("this is function");
}

创建对象

JavaScript中只有一个复杂数据类型那就是object,它既是一个函数也是一个构造函数。

创建对象有三种方式,分别为:

  • 初始化器方式

    创建一个非空对象

    var obj = {
      name: "李磊",
      age: "18",
      sayMe: function () {
        console.log("Hello World");
      },
    };

    创建一个空对象

    var obj1 = {};
  • 构造函数方式

    创建一个非空对象

    var obj = new Object();
    obj.name = "李雷";
    obj.sayMe = function () {
      console.log("this is lilei.");
    };

    创建一个空对象

    var obj2 = new Object();
  • Object.create()方式

    创建一个非空对象

    var obj = Object.create(null);
    obj.name = "李雷";
    obj.sayMe = function () {
      console.log("this is lilei.");
    };

    创建一个空对象

    var obj3 = Object.create(null);

为对象新增属性

var car = {}
car.name = 'ford' //通过点符号为该对象新增属性
car['year'] = 1984 //通过方括号为该对象新增属性

console.log(car)

检测对象属性

  • 将属性值通过全等运算符与 undefined 进行比较
  • 通过 if 语句来判断对象的属性是否存在
  • 使用 in 运算符来判断对象的属性是否存在
  • 使用 Object.hasOwnProperty() 方法来判断对象的属性是否存在
var obj = {
  name: "test",
  age: 123,
};
if (obj.msg === undefined) {
  console.log("与undefined比较");
}
if (!obj.msg) {
  console.log("if判断");
}
console.log("in运算符判断", "msg" in obj);
console.log("hasOwnProperty判断", obj.hasOwnProperty("msg"));

以上代码输出结果为:

与undefined比较
if判断
in运算符判断 false
hasOwnProperty判断 false

构造函数的基本用法

构造函数分为三种,不接受参数的构造函数、接受参数的构造函数与使用属性的构造函数。

  • 不接受参数的构造函数

    function Hero() {
      // 属性
      this.name = "李雷";
      // 方法
      this.sayMe = function () {
        console.log("this is lilei.");
      };
    }
  • 接受参数的构造函数

    function Hero(name) {
      // 属性
      this.name = name;
      // 方法
      this.sayMe = function () {
        console.log("this is lilei.");
      };
    }
  • 使用属性的构造函数

    function Hero(name) {
      // 属性
      this.name = name;
      // 方法
      this.sayMe = function () {
        console.log("this is " + this.name + ".");
      };
    }

在构造函数中的this表示的是初始化的对象。例如声明一个Hero类型的变量,调用是就可以看到编辑器提示的属性了。

var hero = new Hero("lilei");
console.log(hero.name); //打印lilei

函数与构造函数整合在一起

简单来说就是为某个属性设置为函数。

function Score() {
  // 当做函数使用 -> 定义局部变量(初始化默认值)
  var score = 100;
  // 当做构造函数使用
  this.getter = function () {
    return score;
  };
  this.setter = function (new_value) {
    score = new_value;
  };
}
var result = new Score();
console.log(result.getter()); // 100
result.setter(200);
console.log(result.getter()); // 200

因为settergetter都被赋予了函数,因此被称为方法,调用时也自然要加上小括号了。

对象和函数整合在一起

简单来说就是将属性写在对象里,方法写在对象的return里。

function Score() {
  // 局部变量
  var score = 100;
  // 返回一个对象
  return {
    getter: function () {
      return score;
    },
    setter: function (new_value) {
      score = new_value;
    },
  };
}
var result = Score();
console.log(result.getter()); // 100
result.setter(200);
console.log(result.getter()); // 200

删除对象

删除对象使用delete运算符,删除后再次访问则会显示undefined

var user = {
    name: '李雷',
    age: 18
}
delete user.age
console.log(user) //undefined

遍历对象

遍历对象毫无疑问用的是for-in迭代。这样迭代过程中判断是否是方法可以使用instanceof

var obj = {
  name: "李雷", // string
  age: 18, // number
  sayMe: function () {
    console.log("我是李雷.");
  },
};
for (attr in obj) {
  // 如何区分属性和方法?
  if (obj[attr] instanceof Function) {
    console.log("说明当前这个是方法");
  } else {
    console.log("说明当前这个是属性");
  }
}