变量作用域

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

变量提升

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

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

1
2
3
4
var msg;
console.log(msg);
msg=100;
console.log(msg);

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

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

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

1
2
3
4
5
6
7
8
var msg = 100;
function fn() {
console.log(msg); //undefined
var msg = 200;
console.log(msg); //200
}
fn();
console.log(msg); // 100

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

函数提升

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

1
2
3
4
5
fn(); //输出 this is function
function fn() {
console.log("this is function");
}
fn(); // 输出 this is function

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

1
2
3
4
5
6
fn(); 
var fn = function () {
console.log("this is function");
};
fn();
// 报错:TypeError: fn is not a function

变量与函数同名

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

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

创建对象

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

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

  • 初始化器方式

    创建一个非空对象

    1
    2
    3
    4
    5
    6
    7
    var obj = {
    name: "李磊",
    age: "18",
    sayMe: function () {
    console.log("Hello World");
    },
    };

    创建一个空对象

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

    创建一个非空对象

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

    创建一个空对象

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

    创建一个非空对象

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

    创建一个空对象

    1
    var obj3 = Object.create(null);

为对象新增属性

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

console.log(car)

检测对象属性

  • 将属性值通过全等运算符与 undefined 进行比较
  • 通过 if 语句来判断对象的属性是否存在
  • 使用 in 运算符来判断对象的属性是否存在
  • 使用 Object.hasOwnProperty() 方法来判断对象的属性是否存在
1
2
3
4
5
6
7
8
9
10
11
12
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

构造函数的基本用法

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

  • 不接受参数的构造函数

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

    1
    2
    3
    4
    5
    6
    7
    8
    function Hero(name) {
    // 属性
    this.name = name;
    // 方法
    this.sayMe = function () {
    console.log("this is lilei.");
    };
    }
  • 使用属性的构造函数

    1
    2
    3
    4
    5
    6
    7
    8
    function Hero(name) {
    // 属性
    this.name = name;
    // 方法
    this.sayMe = function () {
    console.log("this is " + this.name + ".");
    };
    }

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

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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里。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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

1
2
3
4
5
6
var user = {
name: '李雷',
age: 18
}
delete user.age
console.log(user) //undefined

遍历对象

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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("说明当前这个是属性");
}
}