目录
作用域
作用域:限定所用到的名字可用性的代码范围。提高了程序逻辑的局部性,增强了程序的可靠性,减少了名字冲突。
js的作用域:
- 全局作用域:整个script标签或者是一个单独的js文件
- 局部作用域(函数作用域):在函数内部就是局部作用域,代码的名字只在函数内部起作用
- js没有块级作用域
1. 变量的作用域
根据作用域的不同,可分为:
全局变量
- 在全局作用域下的变量/在函数外部定义的变量
- 在函数内部没有声明而直接赋值的变量
- 全局变量在代码的任何位置都可以使用
- 在任何一个地方都可以使用,只有在浏览器关闭时才会被销毁,因此比较占内存
局部变量
- 在局部作用域下的变量/在函数内部的变量
- 只能在函数内部使用,在函数内部var声明的变量都是局部变量
- 函数的形参也属于局部变量
- 只在函数内部使用,当其所在的代码块被执行时,会被初始化;当代码块运行结束后,就会被销毁,因此更节省内存空间
<script>
// 全局变量,作用在整个script标签内
var num = 10;
function fn() {
//局部变量,在局部作用域下的变量,只能在函数内部使用
var num1 = 10;
//全局变量,在函数内部没有声明而直接赋值
num2 = 20;
}
</script>
2. 作用域链
内部函数访问外部函数的变量,采取的是链式查找的方式来决定取哪个值,就近原则。
结果为:
结果为:
预解析
JavaScript代码是由浏览器中的JavaScript解释器来执行的。JavaScript解析器在运行代码的时候分为两步:预解析和代码执行。
预解析分为变量预解析(变量提升)和函数预解析(函数提升)
- 变量预解析:把所有的变量声明提升到当前的作用域最前面,不提升赋值操作
- 函数预解析:把所有的函数声明提升到当前作用域的最前面,不调用函数
案例1:
<script>
var num = 10;
fun();
function fun() {
console.log(num);
var num = 20;
}
//相当于执行了以下的操作
//1.变量提升
var num;
//2.函数提升
function fun() {
//3. 函数内部变量提升
var num;
console.log(num);
num = 20;
}
//4.赋值、调用函数
num = 10;
//5.根据就近原则,调用函数之后num的值为 undefined
fun();
</script>
案例2:
<script>
var num = 10;
function fn() {
console.log(num);
var num = 20;
console.log(num);
}
fn();
//相当于进行了以下操作,预解析
//1.变量预解析
var num;
//2.函数预解析
function fn() {
//3.函数内部变量预解析
var num;
console.log(num);
num = 20;
console.log(num);
}
//4.变量赋值
num = 10;
//5.调用函数
//根据就近原则 结果为 undefined 20
fn();
</script>
案例3:
<script>
var a = 18;
f1();
function f1() {
var b = 9;
console.log(a);
console.log(b);
var a = '123';
}
//相当于进行了以下操作,预解析
//1.变量提升
var a;
//2.函数提升
function f1() {
//3.函数内部变量提升
var b;
var a;
b = 9;
console.log(a);
console.log(b);
a = '123';
}
//4.变量赋值
a = 10;
//5.调用函数 根据就近原则 结果为 undefined 9
f1();
</script>
案例4:
<script>
f1();
console.log(c);
console.log(b);
console.log(a);
function f1() {
var a = b = c = 9;
//相当于 var a = 9; b = 9; c = 9;
//b和c没有声明,只有赋值
console.log(a);
console.log(b);
console.log(c);
}
//相当于进行了以下操作,预解析
//1.函数提升
function f1() {
//2.函数内部变量提升
var a;
a = 9;
//没有声明,只有赋值,当全局变量看
b = 9;
c = 9;
console.log(a);
console.log(b);
console.log(c);
}
//3.调用函数,所以结果为9 9 9
f1();
//4.由于b、c是全局变量,结果为 9 9 undefined
console.log(c);
console.log(b);
console.log(a);
</script>
对象
对象是一组无序的相关属性和方法的集合,所有事物都是对象,例如字符串、数组、函数等。
对象是由属性和方法组成的
- 属性:事物的特征,在对象中用属性来表示,常用名词
- 方法:事物的行为,在对象中用方法来表示,常用动词
1. 创建对象的三种方式
1)利用字面量创建对象
对象字面量:{ }里面包含了表达这个具体对象的属性和方法。
<script>
//利用字面量{ }创建对象
//1.对象的属性或者方法:键值对->属性名:属性值,
//2.多个属性或者方法之间使用逗号,隔开的
//3.方法冒号后面跟的是一个匿名函数
var obj = {
name: '张三',
age: 18,
sex: '男',
sayHi: function() {
console.log('hi');
}
}
//使用对象
//1.调用对象的属性: 对象名.属性名; 或者 对象名['属性名'];
console.log(obj.name);
console.log(obj['age']);
//2.调用对象的方法:对象名.方法名();
obj.sayHi();
</script>
结果为:
2)利用new object 创建对象
<script>
//利用new Object创建对象
var obj = new Object();
//赋值:利用 = 添加对象的属性和方法,每个属性和方法之间用分号结束
obj.name = '张三';
obj.age = 18;
obj.sex = '男';
obj.sayHi = function() {
console.log('hi');
}
//使用对象
console.log(obj.name);
console.log(obj['age']);
obj.sayHi();
</script>
结果为:
3)利用构造函数创建对象
构造函数:是一种特殊的函数,即为对象成员变量赋初始值,总与new运算符一起使用,可以把对象中一些公共的属性和方法抽取出来,然后封装到这个函数里面。
构造函数抽象了对象的公共部分,封装到了函数里面,泛指某一大类(class);
创建对象,new 构造函数名(),特指某一个,通过new关键字创建对象的过程称为对象的实例化。
<script>
//利用构造函数创建对象
// function 构造函数名() {
// this.属性 = 值;
// this.方法 = function() { }
// }
//new 构造函数名();
//1.构造函数名的首字母要大写
//2.构造的函数不用return,就可以返回结果
function Person(name, age, sex) {
//属性的值 = 传进来的形参 = 实参
this.name = name;
this.age = age;
this.sex = sex;
this.sayHi = function() {
console.log('hi');
}
}
//3.调用构造函数必须使用new
var p = new Person('张三', 18, '男');
console.log(p.name);
console.log(p['age']);
p.sayHi();
</script>
结果为:
2. new关键字
- 在内存中创建一个新的空对象
- 让this指向这个新的对象
- 执行构造函数里面的代码,让这个新对象添加属性和方法
- 返回这个新对象(所以构造函数里面不需要return)
3. 遍历对象属性
for...in语句用于对数组或者对象的属性进行循环操作。
<script>
var obj = {
name: '张三',
age: 18,
sex: '男'
}
// console.log(obj.name);
// console.log(obj.age);
// console.log(obj.sex);
// for (变量 in 对象) {}
for (var k in obj) {
//属性名
console.log(k);
//属性值
console.log(obj[k]);
}
</script>
结果为: