一、作用域与闭包
1. 作用域
1.1 全局作用域
(1) 全局作用域在页面打开时被创建,页面关闭时被销毁
(2) 写在 script 标签中的变量和函数,作用域为全局,在页面的任意位置都可以访问到
(3) 在全局作用域中有全局对象 window,代表一个浏览器窗口,由浏览器创建,可以直接调用
(4) 全局作用域中声明的变量和函数会作为 window 对象的属性和方法保存
// 1. 全局作用域,默认的,不可删除
ver name = 'php中文网';
console.log(name);
// 由全局对象调用的
// 全局对象: 如果在是浏览器中运行js,那么全局对象就是window
console.log(window.name);
复制代码
1.2 函数作用域
(1) 调用函数时,函数作用域被创建,函数执行完毕,函数作用域被销毁
(2) 每调用一次函数就会创建一个新的函数作用域,他们之间是相互独立的
(3) 在函数作用域中可以访问到全局作用域的变量,在函数外无法访问到函数作用域内的变量
(4) 在函数作用域中访问变量、函数时,会先在自身作用域中寻找,若没有找到,则会到函数的上一级作用域中寻找,一直到全局作用域
(5) 在函数作用域中也有声明提前的特性,对于变量和函数都起作用,此时函数作用域相当于一个小的全局作用域
(6) 在函数作用域中,不使用变量关键字声明的变量,在赋值时会往上一级作用域寻找已经声明的同名变量,直到全局作用域时还没找到,则会成为 window 的属性
(7) 在函数中定义形参,等同于声明变量
let site = 'php中文网';
function getSite() {
// site是声明在函数外部的全局变量
// 在函数内部可以访问到外部的全局变量
// let site = "京东商城";
// 私有成员,仅限在当前作用内访问, 外部不可见
let domain = 'php.cn';
return `${site} [ ${domain} ]`;
// 这里要返回一个叫site的变量
// 有一个查询的过程, 先在自身的作用域找一个有没有一个叫site
// 如果有则直接返回它
// 如果函数中没有这个site,则自动函数的上一级作用域中去查看site
// 全局正好有一个site,于是就返回了全局的site
// 内部的site ---> 到它的上一级作用域中去查找
// 上面的查询变量的过程,就是是一个链式查询的一个过程,称为:作用域链
}
console.log(getSite());
复制代码
1.3 块作用域
(1)用{}创建快作用域
(2) let, const 支持块作用域; var 不支持块作用域
{
let a = 1;
const B = 'hello';
// var:不支持块作用域
var c = 1;
}
console.log(a, B, c);
复制代码
2. 闭包
闭包:能够访问自由变量的函数;理论上讲,所有函数都是闭包
let c = 100;
function sum(a, b) {
// 自由变量,函数参数以外的变量;c 为自由变量
return a + b + c;
}
console.log(sum(4, 5));
// 通过闭包来访问内部的私有变量;
function demo1() {
// 私有变量
let email = 'a@qq.com';
return function d() {
// 对于这个子函数来说,email就是它的自由变量
return email;
};
}
console.log(demo1()());
复制代码
二、循环
1. while: 入口判断
const colors = ["red", "green", "blue"];
// 1. while: 入口判断
// 循环变量的初始化
let i = 0;
// i < colors.length: 循环条件
while (i < colors.length) {
// console.log(colors[i]);
console.log("%c%s", "color: red", colors[i]);
// 更新循环条件,如果不更新就进入了死循环
// i = i + 1;
// i += 1;
// 自增1
i++;
// i+=2;
}
复制代码
2. while: 出口判断
const colors = ["red", "green", "blue"];
// 2. while: 出口判断
// 当条件不满足的时候至少执行一次
// 循环变量的初始化
i = 10;
// i < colors.length: 循环条件
do {
console.log("%c%s", "color: blue", colors[i]);
console.log("我被执行了一次");
// 更新循环条件,如果不更新就进入了死循环
i++;
} while (i < colors.length);
复制代码
3. 对象的遍历 for-in
// 3. 对象的遍历, for -in
const lesson = { "my name": "JavaScript编程", score: 88 };
console.log(lesson);
for (let key in lesson) {
console.log(lesson[key]);
}
复制代码
4. for 循环
// 4. for 循环
const colors = ["red", "green", "blue"];
// 循环变量的初始化
i = 0;
// i < colors.length: 循环条件
while (i < colors.length) {
// console.log(colors[i]);
console.log("%c%s", "color: red", colors[i]);
// 更新循环条件,如果不更新就进入了死循环
// i = i + 1;
// i += 1;
// 自增1
i++;
// i+=2;
}
// while的简化版
for (i = 0; i < colors.length; i++) {
console.log("%c%s", "color: green", colors[i]);
}
复制代码
5.迭代器 for-of,遍历数组
// 迭代器,将所有类型的数据的遍历进行了统一操作
// for - of
// 遍历数组
const colors = ["red", "green", "blue"];
for (let item of colors) {
console.log(item);
}
// 遍历对象,会报错
const lesson = { "my name": "JavaScript编程", score: 88 };
for (let item of lesson) {
console.log(item);
}
复制代码
三、迭代器
function myIterator(data) {
// 迭代器中必须要有一个next()
let i = 0;
return {
next() {
// done: 表示遍历是否完成?
// value: 当前正在遍历的数据
let done = i >= data.length;
let value = !done ? data[i++] : undefined;
return { done, value };
},
};
}
let iterator = myIterator(["html", "css", "js", "php"]);
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
复制代码
四、构造函数和原型
// 常识: 任何一个函数都是对象,有一个属性叫: prototype(原型属性)
function f1(a, b, c) {}
console.dir(f1);
// 函数有二个功能
// 基本功能是封装操作步骤
// 扩展功能: 当成对象的构造器,构造函数,对象生成器来用
// 在js中没有“类”的概念,都是通过原型来实现继承的
// 为了区别函数的这二个功能,当一个函数当成构造函数来使用时,必须使用“new"来调用
// 通过构造函数创建对象的过程,叫”类的实例化"
// 此时,构造函数就可以看成一个类
function User(name, email) {
// 1.内部会自动创建一个this,指向新生成的对象
// let this = new User();
// 2.第二步是给这个新生成的对象添加一些成员(属性,方法)
this.name = name;
this.email = email;
// 3.返回这个新对象
// return this;
}
// 当成普通函数调用
// const user = User();
// 当成构造函数调用 new
const user = new User("admin", "admin@php.cn");
console.log(user, typeof user);
// user对象的原型属性永远指向它的构造函数的原型属性对象
// user对象的原型
console.log(user.__proto__);
// user的构造函数的原型
console.log(User.prototype);
console.log(user.__proto__ === User.prototype);
复制代码
五、类与类的继承
1.类: 使用 class 关键字
class User1 {
// 构造方法:初始化对象的
constructor(name, email) {
this.name = name;
this.email = email;
}
// 原型方法(共享方法),通过对象来调用的
show() {
return { name: this.name, email: this.email, age: this.#age };
}
// 静态方法: 不需要实例化(new class),直接用类来调用
static fetch() {
// 静态成员中的this表示的就是当前的类
return this.userName;
}
// 静态属性/变量
static userName = '灭绝小师妹';
// 私有成员
#age = 50;
// 还可以声明访问器属性: 伪装成属性的方法,有get,set
// 使用访问器属性来访问私有成员
get age() {
return this.#age;
}
set age(value) {
if (value >= 18 && value < 60) this.#age = value;
else console.log('年龄非法');
}
}
const user1 = new User1('天蓬老师', 'tp@qq.com');
console.log(user1.show());
// 静态方法直接用类调用
console.log(User1.fetch());
console.log('my age = ', user1.age);
user1.age = 160;
console.log('my age = ', user1.age);
user1.age = 32;
console.log('my age = ', user1.age);
复制代码
2.继承:使用 extends 关键字
// 继承,通常是对父类进行一些扩展(添加一些新的属性或方法)
class Child extends User1 {
constructor(name, email, gender) {
// 第一步必须将父类的构造方法来执行一下,否则this用不了
super(name, email);
// 第二步给子类的新成中去初始化
this.gender = gender;
}
// 父类的原型方法
show() {
return { name: this.name, email: this.email, gender: this.gender };
}
}
const child = new Child('欧阳老师', 'oy@qq.com', '男');
console.log(child.show());
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END