1. 全局变量:
在全局作用域下的变量,在全局下都可以使用
注意: 如果在函数内部 没有声明直接赋值的变量也属于全局变量
2. 局部变量:
在局部作用域下的变量,后者在函数内部的变量就是 局部变量
var num = 5; //全局变量
function fun(aru){ //🔴函数的形参 aru 也看作是局部变量
var num1 = 10; // num1就是局部变量 只能在函数内部使用
num2 = 20; //没有在内部声明,也算是全局变量🔴
console.log(num);
}
fun();
//console.log(num1); // ❌出错 因为是局部变量
console.log(num2);
function f1(){
var a = b = c = 9;
//相当于以下 ❗ ❗
var a = 9; b = 9; c = 9; // b 和 c 直接赋值,当全局变量看 ✅
//而不是以下 以下是集体声明
var a = 9, b = 9, c = 9; // 此时才相当于 var a; var b; var c;😱
}
JS 没有块级作用域
- 块作用域由 { } 包括
- 在其他编程语言中(如 java、c#等),在 if 语句、循环语句中创建的变量,仅仅只能在本 if 语句、本循环语句中使用,
如下面的Java代码:
if(true){
int num = 123;
system.out.print(num); // 123
}
system.out.print(num); // 报错
Js中没有块级作用域(在ES6之前)
if(true){
var num = 123;
console.log(123); //123
}
console.log(123); //123
作用域链
只要是代码都一个作用域中,写在函数内部的局部作用域,未写在任何函数内部即在全局作用域中;如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域;根据在[内部函数可以访问外部函数变量]的这种机制,用链式查找决定哪些数据能被内部函数访问,就称作作用域链
作用域链:采取就近原则的方式来查找变量最终的值。
var a = 1;
function fn1() {
var a = 2;
var b = '22';
fn2();
function fn2() {
var a = 3;
fn3();
function fn3() {
var a = 4;
console.log(a); //a的值 ?
console.log(b); //b的值 ?
}
}
}
fn1();
预解析
- js 引擎运行 js 分为两步: 预解析 、 代码执行
(1)预解析: js 引擎会把 js 里面所有的 var 还有 function 提升到当前作用域的最前面 (其他的依次排列即可)
(2)代码执行: 按照代码书写的顺序从上往下执行 - 预解析 分为 :变量预解析(变量提升) 、 函数预解析(函数提升)
(1)变量提升:就是把所有的变量声明提升到当前的作用域最前面 不提升赋值操作
(2)函数提升:就是把所有的函数声明提升到当前的作用域最前面 不调用函数
预解析+作用域链 ➡一起使用
例1:
console.log(num); // ❌ undefined 坑1
var num = 10;
//相当于执行了以下代码
var num; //变量提升
console.log(num);
num = 10;
例2:
函数表达式创建函数,会执行变量提升,此时接收函数的变量名无法正确的调用:
fun(); // ❌ fun is not a function 报错 坑2
var fun = function(){
console.log(22);
}
//相当于执行了以下代码
var fun; //变量提升
fun();
fun = function(){
console.log(22);
}
例3
fn(); // ✅ 成功显示 11
function fn(){
console.log(11);
}
//相当于执行了以下代码
function fn(){
console.log(11);
}
fn();
例4
var a = 18;
f1();
function f1() {
var b = 9;
console.log(a); // undefined ❓❓
console.log(b); // 9
var a = '123';
}
//相当于以下代码 (为什么 a 是 undefined ?)
var a;
function f1() {
var b;
var a;
b = 9;
console.log(a); // undefined ❗
console.log(b); // 9
a = '123';
}
a = 18;
f1();
例5
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);
}
// 相当于以下 ❗ ❗
function f1() {
var a; // 声明了 a
a = b = c = 9;
console.log(a); // 9
console.log(b); // 9
console.log(c); // 9
}
f1();
console.log(c); // 9 c 为全局变量
console.log(b); // 9 b 为全局变量
console.log(a); // 报错 a 为局部变量
对象
1. 什么是对象?
对象是一个具体的事物,
在 JavaScript 中,对象是一组无序的相关属性和方法的集合,所有的事物都是对象,例如字符串、数值、数组、函数等。
❎:明星、 女朋友、 班主任、 苹果、 手机、 游戏
✅:周星驰、迪丽热巴、咱们班主任、这个苹果、我的手机、刺激战场
对象是由**属性**和**方法**组成的。
属性:事物的特征,在对象中用属性来表示(常用名词)
方法:事物的行为,在对象中用方法来表示(常用动词)
2.为什么需要对象?
保存一个值时,可以使用变量,保存多个值(一组值)时,可以使用数组。
为了让更好地存储一组数据,对象应运而生:对象中为每项数据设置了属性名称,可以访问数据更语义化,数据结构清晰,表意明显,方便开发者使用。
创建对象的三种方式
1.利用字面量创建对象
就是花括号 { } 里面包含了表达这个具体事物(对象)的属性和方法;{ } 里面采取键值对的形式表示
键:相当于属性名
值:相当于属性值,可以是任意类型的值(数字类型、字符串类型、布尔类型,函数类型等)
1).利用对象字面量创建对象 { }
(1)里面的属性或者方法 我们采取键值对的形式 键 属性名 : 值 属性值
(2)多个属性或方法中间用逗号隔开
(3)方法冒号后面跟的是一个匿名函数
2).使用对象
(1)调用对象的属性 我们采用 对象名.属性名 **.**我们理解为 的
(2)调用属性还有一种方法 对象名[‘属性名’]
(3)调用对象的方法 对象名.方法名() 千万别忘记添加小括号
//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']);
//(3)调用对象的方法 对象名.方法名() 千万别忘记添加小括号
obj.sayHi();
变量、属性、函数、方法的区别
变量和属性
- 相同:都是用来存储数据的。
- 不同:
- 变量:单独声明赋值,单独存在,使用的时候直接写变量名
- 属性:对象里面的变量称为属性,不需要声明,用来描述该对象的特征,使用时必须是 对象.属性
函数和方法
- 相同:都是实现某种功能 做某件事
- 不同:
- 函数:单独存在的,通过“函数名()”的方式就可以调用
- 方法:对象里面的函数称为方法,方法不需要声明,使用“对象.方法名()”的方式就可以调用,方法用来描述该对象的行为和功能。
var num = 10; // 变量
var obj = {
age:18 //属性
sayHi: function(){ //方法
console.log('hi~');
}
}
function fn(){ //函数
console.log('ok~');
}
}
console.log(num);
console.log(age);
2.利用 new Object 创建对象
//创建空对象
var andy = new Object();
//给空对象添加属性和方法
andy.name = 'pink';
andy.age = 18;
andy.sex = '男';
andy.sayHi = function(){
alert('大家好啊~');
}
注意:
- Object() :第一个字母大写
- new Object() :需要 new 关键字
- 使用的格式:对象.属性 = 值;
3.利用 构造函数 创建对象
注意事项
- 构造函数约定首字母大写。
- 函数内的属性和方法前面需要添加 this ,表示当前对象的属性和方法。
- 构造函数中不需要 return 返回结果。
- 当我们创建对象的时候,必须用 new 来调用构造函数。
其他
- 构造函数,如 Stars(),抽象了对象的公共部分,封装到了函数里面,它泛指某一大类(class)
- 创建对象,如 new Stars(),特指某一个,通过 new 关键字创建对象的过程我们也称为对象实例化
new关键字的作用
- 在构造函数代码开始执行之前,创建一个空对象
- 修改this的指向,把this指向创建出来的空对象;执
- 行函数的代码
- 在函数完成之后,返回this—即创建出来的对象
// 利用构造函数创建对象
// 我们需要创建四大天王的对象 相同的属性: 名字 年龄 性别 相同的方法: 唱歌
// 构造函数的语法格式
// function 构造函数名() {
// this.属性 = 值;
// this.方法 = function() {}
// }
// new 构造函数名();
function Star(uname, age, sex) {
this.name = uname;
this.age = age;
this.sex = sex;
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('冰雨');
var zxy = new Star('张学友', 19, '男');
console.log(zxy.name);
console.log(zxy.age);
zxy.sing('李香兰')
// 1. 构造函数名字首字母要大写
// 2. 我们构造函数不需要return 就可以返回结果
// 3. 我们调用构造函数 必须使用 new
// 4. 我们只要new Star() 调用函数就创建一个对象 ldh {}
// 5. 我们的属性和方法前面必须添加 this
// 构造函数和对象
// 1. 构造函数 明星 泛指的某一大类 它类似于 java 语言里面的 类(class)
function Star(uname, age, sex) {
this.name = uname;
this.age = age;
this.sex = sex;
this.sing = function(sang) {
console.log(sang);
}
}
// 2. 对象 特指 是一个具体的事物 刘德华 == {name: "刘德华", age: 18, sex: "男", sing: ƒ}
var ldh = new Star('刘德华', 18, '男'); // 调用函数返回的是一个对象
console.log(ldh);
// 3. 我们利用构造函数创建对象的过程我们也称为对象的实例化