目录
一、作用域
1.作用域
1.1作用域
1.2全局作用域
1.3局部作用域
1.4JS没有块级作用域
2.变量的作用域
2.1全局变量
2.2局部变量
2.3全局变量和局部变量的区别
3.作用域链
二、预解析
1.预解析相关概念
1.1预解析和代码执行
1.2 变量预解析(变量提升)
1.3函数预解析(函数提升)
案例:(案例4重点)
三、对象
1.对象
1.1对象是由属性和方法组成的
1.2为什么需要对象
2.创建对象的三种方式
2.1 利用字面量创建对象
2.2 利用new Object创建对象
2.3 利用构造函数创建对象
3.new关键字的作用(面试题)
4.遍历对象
就是代码名字(变量)在某个范围内起作用和效果 ,目的是为了提高程序的可靠性,减少命名冲突。
ES6之前作用域有两种 全局作用域
和局部作用域
(函数作用域)
作用于所有代码执行的环境(整个 script 标签内部)或者一个独立的js文件。
作用于函数内部的代码环境,就是局部作用域。因为跟函数有关系,所以也被称为函数作用域
。
块作用域由 {} 包括
在其他编程语言,if语句中,循环语句创建的变量,仅仅只能在本if语句,本循环语句中使用,如下
if(true){
int num = 123;
System.out.print(num); //123
}
System.out.print(num);//报错
以上java代码会报错,因为代码中 {}是一块作用域,其中声明的变量num,在{}之外不能使用,而JavaScript代码则不会报错
js在 es6 的时候新增的块级作用域(简而言之,变量在函数外可以调用)
if(true){
var num = 123;
console.log(num); // 123
}
console.log(num);// 123
在JavaScript中,根据作用域的不同,变量可以分为两种:
全局变量
局部变量
在全局作用域下声明的变量(在函数外部定义的变量)
全局变量在代码的任何位置都可以使用
在在全局作用域下var声明的变量(在函数外部定义的变量)是全局变量
!!特殊情况下,如果在函数内部 没有声明(不使用var声明)直接赋值的变量也属于全局变量 (不建议使用)
在局部作用域下声明的变量(在函数内部var声明的变量)
局部变量只能在函数内部使用
函数的形参也可以看做是局部变量
全局变量:
在任何一个地方都可以使用,只有在浏览器关闭时才会销毁,因此比较占内存
局部变量:
旨在函数内部使用,当其所在的代码块被执行时,才会被初始化;当代码块运行结束后,就会被销毁,因此更节省内存空间。
[内部函数可以访问外部函数变量]
的这种机制,用链式查找(一层一层往外查找即就近原则)决定哪些数据能被内部函数访问,就称作作用域链。作用域链
采取就近原则的方式来查找变量最终的值 // 作用域链 : 内部函数访问外部函数的变量,采取的是链式查找的方式来决定取哪个值
var num = 10; //全局变量
function fn() { //外部函数
var num = 20; //局部变量
num1 = 30; // !!全局变量(如果在函数内部 没有声明直接赋值的变量也属于全局变量 )
function fun() { //内部函数
console.log(num); //num采取就近原则
}
fun();
}
fn(); //20
console.log(num1); // 30
// 案例2:结果是几?
function f4() {
var num = 123;
function f5() {
console.log(num // 站在目标出发,一层一层往外查找
}
f5(); // 123
}
var num = 456;
f4() // 无输出,要有输出还得调用函数f5
JavaScript代码是由浏览器中的JavaScript解析器来执行的。JavaScript解析器在运行JavaScript代码的时候分为两步:预解析和代码执行。
预解析在当前作用域下,JS代码执行之前,浏览器会默认把带有 var 和 function声明的变量在内存中进行提前声明或定义。预解析分为变量预解析(变量提升)和函数预解析(函数提升)
代码执行 从上往下执行JS语句
预解析会把变量和函数的声明在代码执行之前完成,预解析也叫做变量、函数提升。
所有变量声明会被提升到当前作用域的最上面,变量的赋值不提升。
函数的声明会被提升到当前作用域的最上面,但是不会调用函数。
// 1.
console.log(num); //报错
// 2.先进行变量提升
console.log(num); //underfined
var num = 10;
// 相当于执行力以下代码
// var num; // 先进行变量提升(所有变量声明会被提升到当前作用域的最上面,变量的赋值不提升)
// console.log(num);
// num = 10;
//3. 函数提升(函数的声明会被提升到当前作用域的最上面,但是不会调用函数)
fn();
function fn() {
console.log(11); // 11
}
// 相当于执行力以下代码
// function fn() {
// console.log(11);
// }
// fn();
// 4. 先进行变量提升
fun();
var fun = function() {
console.log(22); // 报错
}
// 相当于执行力以下代码
// var fun;
// fun(); // 因为fun并没有被赋值,调用时就肯定会报错
// fun = function() {
// console.log(22);
// }
// 案例1
var num = 10;
fun();
function fun() {
console.log(num); // underfined
var num = 20;
}
// 相当于执行了以下操作
var num; // 变量提升(变量声明会被提升到当前作用域的最上面 !!!当前作用域)
function fun() {
var num;
console.log(num); // underfined
num = 20;
}
num = 10;
fun();
// 案例2
var num = 10;
function fn() {
console.log(num); // underfined
var num = 20;
console.log(num); // 20
}
fn();
// 相当于执行了以下操作
// var num;
// function fn() {
// var num;
// console.log(num); // underfined
// num = 20;
// console.log(num); // 20
// }
// num = 10;
// fn();
// 案例3
var a = 18;
f1();
function f1() {
var b = 9;
console.log(a); // underfined
console.log(b); // 9
var a = '123';
}
// 相当于执行了以下操作
// var a;
// function f1() {
// var b;
// var a;
// b = 9;
// console.log(a); // underfined
// console.log(b); // 9
// var a = '123';
// }
// a = 18;
// f1();
// 案例4
f2();
console.log(c);
console.log(b);
console.log(a);
function f2() {
var a = b = c = 9;
// 相当于 var a = 9; b = 9; c = 9; b和c直接赋值,没有var声明,当全局变量看
// 集体声明 var a = 9, b = 9, c = 9;(此时a,b,c都用var声明了)
console.log(a);
console.log(b);
console.log(c);
}
// 相当于执行了以下操作
// function f2() {
// var a;
// a = b = c = 9;
// console.log(a); // 9
// console.log(b); // 9
// console.log(c); // 9
// }
// f2();
// console.log(c); // 9
// console.log(b); // 9
// console.log(a); // 报错(因为a是局部变量)
在JavaScript中,对象是一组无序的相关属性和方法的集合,所有的事物都是对象,例如字符串、数值、数组、函数等。
属性:事物的特征,在对象中用属性来表示(常用名词)
方法:事物的行为,在对象中常用方法来表示(常用动词)
保存一个值时,可以使用变量,保存多个值(一组值)时,可以使用数组,如果保存一个的完整信息呢?
为了更好地存储一组数据,对象应用而生;对象中为每项数据设置了属性名称,可以访问数据更语义化,数据结构清晰,表意明显,方便开发者使用。
对象字面量:就是花括号 { } 里面包含了表达这个具体事物(对象)的属性和方法;{ } 里面采取键值对的形式表示
-键
:相当于属性名
-值
:相当于属性值,可以是任意类型的值(数字类型、字符串类型、布尔类型,函数类型等)
// 1.利用对象字面量创建对象 {}
//var obj = {}; // 创建了一个空的对象
var obj = {
uname: '漓曦',
age: 18,
sex: '女',
sayHi: function() {
console.log('hi~');
}
}
// 1) 里面的属性或者方法采取键值对的形式 键(属性名):值(属性值)
// 2) 多个属性或者方法中间用逗号隔开
// 3) 方法冒号后面跟的是一个匿名函数
// 2. 使用对象
// 1)调用对象的属性,采取 对项名.属性名 “.”可以理解为“的”
console.log(obj.uname); // 漓曦
// 2)调用属性还有一种方法 对象名['属性名']
console.log(obj['age']); // 18
// 3) 调用对象的方法 对象名.方法名() 注意调用函数要加小括号
obj.sayHi(); // hi~
变量、属性、函数、方法总结:①变量
:单独声明赋值,单独存在,使用时直接写变量名②属性
:对象里面的变量称为属性,不需要声明,用来描述该对象的特征。使用时必须 对象.属性③方法
:方法是对象的一部分,函数不是对象的一部分,函数是单独封装操作的容器。对象里面的函数称为方法,方法不需要声明,使用"对象.方法名()"的方式就可以调用,方法用来描述该对象的行为和功能。④函数
:单独存在的,通过"函数名()"的方式就可以调用。
// 利用 new Object 创建对象
var obj = new Object(); // 创建了一个空的对象 object中的O要大写
obj.uname = '漓曦';
obj.age = 18;
obj.sex = '女';
obj.sayHi = function() {
console.log('hi~');
}
// 1) 利用 等号 = 赋值 的方法 添加对象的属性和方法
// 2)每个属性和方法之间用 分号 结束
console.log(obj.name);
console.log(obj['sex']);
obj.sayHi();
构造函数
是一种特殊的函数,主要用来初始化对象,即为对象成员变量赋初始值,它总与new运算符一起使用,我们可以把对象中一些公共的(相同的)属性和方法抽出来,然后封装到这个函数里面
// 为什么需要使用构造函数
// 就是因为前面两种创建对象的方式一次只能创建一个对象
// 利用 构造函数 创建对象
// 构造函数的语法格式
// function 构造函数名() {
// this.属性 = 值; // this表示当前的 必须添加
// this.方法 = function() {}
// }
// new 构造函数名(); // 调用构造函数 必须使用 new
function Star(uname1,age1,sex1) {
this.name = uname1;
this.age = age1;
this.sex =sex1;
this.sing = function(sang) {
console.log(sang);
}
}
var ldh = new Star('刘德华',18,'男');
// console.log(typeof ldh); // object 调用函数返回的是一个对象
console.log(ldh.name); // 刘德华
console.log(ldh['sex']); // 男
ldh.sing('冰雨'); // 冰雨
// 1.构造函数名字 的首字母要大写
// 2.构造函数不需要 return 就可以返回结果
// 1.其他:构造函数如Stars(),抽取了对象的公共部分,封装到了函数里面,它泛指某一大类(class)
// 2.创建对象,如new Stars();特指某一个,利用new关键字创建对象的过程,我们也称为对象实例化
1.在构造函数代码开始执行之前,创建一个空对象;
2.修改this的指向,把this指向创建出来的空对象;
3.执行构造函数内的代码,给这个新对象添加属性和方法
4.在函数完成之后,返回这个创建出来的新对象(所以构造函数里面不需要return)
for...in 语句用于对数组或者对象的属性进行循环操作。
其语法如下:
for (变量 in 对象名字) {
// 在此执行代码
}
语法中的变量是自定义的,它需要符合命名规范,通常我们会将这个变量写为 k 或者 key。
var obj = {
name: '漓曦',
age: 18,
sex: '女',
}
for (var k in obj) {
console.log(k); // k 变量 输出 得到的是属性名 (k不加引号)
console.log(obj[k]); // obj[k] 得到的是属性值
}