【javaScript】学完js基础,顺便把js高级语法学了(尚硅谷视频学习笔记)

article/2025/6/7 5:42:31

文章目录

    • 【1】基本总结深入
      • 一、什么是数据
        • 1、数据类型
          • 基本(值)类型
          • 对象(引用)类型
        • 2、判断
        • 相关问题
      • 二、什么是内存
          • 1、什么是数据
          • 2、什么是内存?
          • 3、什么是变量
          • 4、内存、数据、变量三者之间的关系
          • 相关问题
            • 1、问题:var a = xxx,a内存中到底保存的是什么?
            • 2、关于引用变量赋值问题
            • 3、在js调用函数传递变量参数时,是值传递还是引用传递
            • 4、JS引擎如何管理内存
      • 三、什么是对象
          • 1、什么是对象
          • 2、为什么要用对象
          • 3、对象的组成
          • 4、如何访问对象内部数据
          • 5、什么时候必须使用[‘属性值’]的方式
      • 四、什么是函数
          • 1、什么是函数
          • 2、为什么用函数
          • 3、如何定义函数
          • 4、如何调用(执行)函数
          • 5、回调函数
            • 1、什么函数才是回调函数
            • 2、常见的回调函数
          • 6、IIFE
            • 1、理解
            • 2、作用
          • 7、函数中的this
            • 1、this是什么
            • 2、如何让确定this的值
    • 【2】函数高级
      • 一、原型与原型链
        • 1、原型
          • (1)函数的prototype属性
          • (2)给原型对象添加属性(一般都是方法)
        • 2、显示原型与隐式原型
          • (1)每个函数function都有一个prototype,即显示原型(属性)默认指向一个空的Object对象
          • (2)每个实例对象都有一个‘ _ _ proto _ _’,可称为隐式原型(属性)
          • (3)对象的隐式原型的值为其对应构造函数的显式原型的值
          • (4)内存构造(图)
          • (5)总结
        • 3、原型链
          • (1)原型链
          • (2)构造函数/原型实例对象的关系
          • (3)构造函数/原型实例对象的关系2
          • (4)相关问题
        • 4、原型链属性问题
        • 5、探索instanceof
          • 1、instanceof是如何判断的?
          • 2、Function是通过new自己产生的实例
        • 6、面试题
      • 二、执行上下文与执行上下文栈
        • 1、变量提升与函数提升
          • (1)变量声明提升
          • (2)函数声明提升
        • 2、执行上下文
          • (1)代码分类(位置)
          • (2)全局执行上下文
          • (3)函数执行上下文
        • 3、执行上下文栈
          • (1)在全局代码执行前,JS引擎就会创建一个栈来存储管理所有的执行上下文对象
          • (2)在全局执行上下文(window)确定后,将其添加到栈中(压栈)
          • (3)在函数执行上下文创建后,将其添加到栈中(压栈)
          • (4)在当前函数执行完后,将栈顶的对象移除(出栈)
          • (5)当所有的代码执行完后,栈中只剩下window
        • 4、面试题
      • 三、作用域与作用域链
        • 1、作用域
          • (1)理解
          • (2)分类
          • (3)作用
        • 2、作用域与执行上下文
          • (1)区别1
          • (2)区别2
          • (3)联系
        • 3、作用域链
          • (1)理解
          • (2)查找一个变量的查找规则
      • 四、闭包
        • 1、理解闭包
          • (1)如何产生闭包
          • (2)闭包到底是什么
          • (3)产生闭包的条件
        • 2、常见闭包
        • 3、闭包作用
          • (1)使用函数内部的变量在函数执行完后,仍然存活在内存中(延长了局部变量的声明周期)
          • (2)让函数外部可以操作(读写)到函数内部的数据(变量/函数)
          • (1)函数执行完后,函数内部声明的局部变量是否还存在?
          • (2)在函数外部能直接访问函数内部的局部变量吗?
        • 4、闭包生命周期
          • (1)产生:在嵌套内部函数定义执行完时就产生了(不是在调用)
          • (2)死亡:在嵌套的内部函数成为垃圾对象时
        • 5、闭包应用
          • 闭包的应用:定义JS模块
        • 6、闭包缺点
          • (1)缺点
          • (2)解决
          • (3)内存溢出
          • (4)内存泄漏
        • 五、面试题
    • 【3】对象高级
      • 一、对象创建模式
        • 方式一:Object构造函数模式
        • 方式二:对象字面量模式
        • 方式三:工厂模式
        • 方式四:自定义构造函数模式
      • 二、继承模式
        • 1、原型链继承
          • (1)套路
          • (2)关键
        • 2、借用构造函数继承(假的)
          • (1)套路
          • (2)关键
        • 3、组合继承
          • (1)原型链+借用构造函数的组合继承
    • 【4】线程机制与事件机制
      • 一、进程与进程
        • 1、进程
          • 2、线程
        • 3、图解
        • 4、相关知识
        • 5、相关问题
          • (1)何为多进程与多线程
          • (2)JS是单线程还是多线程
          • (3)比较单线程与多线程
          • (4)浏览器运行是单线程还是多线程
      • 二、浏览器内核
      • 三、定时器引发的思考
        • 1、定时器真的是定时执行的吗?
        • 2、定时器回调函数是在哪个线程执行的?
        • 3、定时器是如何实现的?
      • 四、JS是单线程执行
      • 五、浏览器的事件循环(轮询)模型

【1】基本总结深入

一、什么是数据

1、数据类型

  • 基本(值)类型
    • String:任意的字符串
    • Nubmer:任意数字
    • booleans :true/false
    • undefined:undefined
    • null:null
  • 对象(引用)类型
    • Object:任意对象
    • Function:一种特别的对象(可以执行)
    • Array:一种特别的对象(数值下标,内部数据是有序的)

2、判断

  • typeof 返回数据类型的字符串表达

    • 可以判断:underfine/数值/字符串/布尔值/function
    • 不能判断:null与object, object与array
    var b1 = {b2:[1,'abc',console.log],b3:function(){console.log('b3')return function(){return 'xfzhang'}}
    }console.log(typeof b1.b2)//'object'
    
  • instanceof

    • 判断对象的基本类型
  • ===

    • 可以判断:undefine,null

相关问题

1、underfine与null的区别

  • underfine 代表定义未赋值
  • null定义了并赋值,值为null

2、 什么时候给变量赋值为null呢?

  • 初始赋值,表明将要赋值为对象
  • 结束前,让对象成为垃圾对象(被垃圾回收器回收)

3、严格区别变量类型与数据类型

  • 数据类型

    • 基本类型
    • 对象类型
  • 变量的类型(变量内存值的类型)

    • 基本类型:保存就是基本类型的数据
    • 引用类型:保存的是地址值

二、什么是内存

1、什么是数据
  • 存储在内存中代表特定信息的东西,本质上是0101……
  • 数据的特点:可传递,可运算
  • 一切皆数据
  • 内存中所有操作的目标:数据
    • 算术运算
    • 逻辑运算
    • 赋值
    • 运行函数
2、什么是内存?
  • 内存条通电后产生的可存储数据的空间(临时的)

  • 内存的产生和死亡:内存条==>通电==>产生内存空间==>存储数据==>处理数据==>断电==>内存空间和数据都消失

  • 一块小内存的2个数据

    • 内部存储的数据
    • 地址值
  • 内存分类

    • 栈:全局变量/局部变量(空间较小)
    • 堆:对象(空间较大)
3、什么是变量
  • 可变化的量,由变量名和变量值组成
  • 每个变量都对应的一块小内存,变量名用来查找对应的内存,变量值就是内存中保存的数据
4、内存、数据、变量三者之间的关系
  • 内存是用来存储数据的空间
  • 变量是内存的标识
相关问题
1、问题:var a = xxx,a内存中到底保存的是什么?
  • xxx是基本数据,保存的就是这个数据
  • xxx是对象,保存的是对象的地址值
  • xxx是一个变量,保存的xxx的内存内容(可能是基本数据,也可能是地址值)
2、关于引用变量赋值问题
  • 2个引用变量指向同一个对象,通过一个变量修改对象内部数据,另一个变量看到的是修改之后的数据
  • 2个引用变量指向同一个对象,让其中一个引用变量指向另一个对象,另一个对象依然指向前一个对象。
var obj1 = {name:'Tom'}
var obj2 = obj1;
function fn1(obj) {obj.name = 'A';
}
fn1(obj1)
console.log(obj2.name)//A
function fn2(obj) {obj = {name: 'B'}
}
fn2(obj1)
console.log(obj1.name) //A
3、在js调用函数传递变量参数时,是值传递还是引用传递
  • 理解1:都是值(基本/地址值)传递
  • 理解2:可能值传递,也可能是引用传递(地址值)
4、JS引擎如何管理内存

1、内存生命周期

  • 分配小内存空间,得到它的使用权
  • 存储数据,可以反复进行操作
  • 释放小内存空间

2、释放内存

  • 局部变量:函数执行完自动释放
  • 对象:成为垃圾对象==>由垃圾回收器回收
var a = 3
var obj = {}
function fn() {var b = {}
}
fn()//b是自动释放,b所指向的对象是在后面的某个时刻由垃圾回收器回收

三、什么是对象

1、什么是对象
  • 多个数据的封装体
  • 用来保存多个数据的容器
  • 一个对象代表现实中的一个事物
2、为什么要用对象
  • 统一管理多个数据
3、对象的组成
  • 属性:属性名(字符串)和属性值(任意)组成
  • 方法:一种特别的属性(属性值是函数)
4、如何访问对象内部数据
  • 属性名:编码简单,有时不能用
  • [‘属性名’]:编码麻烦,能通用
5、什么时候必须使用[‘属性值’]的方式

​ 1、属性名包含特殊字符: - 空格

​ 2、属性值不确定

var p = {}
//1、给p对象添加一个属性:content type: text/json
//p.content-type = 'text/json' //不能用
p['content-type'] = 'text/json'var propName = 'myAge'
var value = 18
//p.propName = value //不能用
p[propName] = value
console.log(p[propName])

四、什么是函数

1、什么是函数
  • 实现特定功能的n条语句的封装体
  • 只有函数是可以执行的,其他类型的数据不能执行
2、为什么用函数
  • 提高代码复用

  • 便于阅读交流

3、如何定义函数
//1.函数声明
function fn1() {console.log(1)
}
//2.表达式
fn2 = function() {console.log(2)
}
4、如何调用(执行)函数
  • test():直接调用
  • obj.test():通过对象调用
  • new test():new调用
  • test.call/apply(obj):临时让test成为obj的方法调用
var obj = {}
function test(){this.xxx="atguigu"
}
//obj.test() 不能直接调用
test.call(obj) //相当于obj.test()
console.log(obj.xxx) // atguigu
5、回调函数
1、什么函数才是回调函数
  • 你定义的
  • 你没有调用
  • 最终它执行了
2、常见的回调函数
  • dom事件回调函数
  • 定时器回调函数
  • ajax请求回调函数
  • 生命周期回调函数
6、IIFE
1、理解
  • 全称:Imm-Invoked Function Expression
2、作用
  • 隐藏实现
  • 不会污染外部(全局)命名空间
(function () { //匿名函数调用var a = 3console.log(a + 3)
})()
var a = 4
console.log(a)
;(function () {var a = 1function test () {console.log(++a)}window.$ = function () { //向外暴露一个全局函数return {test:test}}
})()
$.test() //1. $是一个函数 2.$执行后返回的是一个对象//6
//4
//2
7、函数中的this
1、this是什么
  • 任何函数本质上都是通过某个对象来调用的,如果没有直接指定就是window
  • 所有函数内部都有一个变量this
  • 它的值是调用函数的当前对象
2、如何让确定this的值
  • test():window
  • p.test():p
  • new test():新创建的对象
  • p.call(obj):obj
function Person(color) {console.log(this)this.color = color;this.getColor = function () {console.log(this)return this.color };this.setColor = function () {console.log(this)return this.color };
}
Person("red"); //this是谁? windowvar p = new Person("yello");  //this是谁? pp.getColor(); //this是谁? pvar obj = {};
p.serColor.call(obj,"black"); //this是谁? objvar test = p.setColor;
test(); //this是谁? windowfunction fn1() {function fn2() {console.log(this);}fn2();//this是谁? window
}
fn1;

【2】函数高级

一、原型与原型链

1、原型

(1)函数的prototype属性
  • 每个函数都有一个prototype属性,它默认指向一个Object空对象(原型对象)
  • 原型对象中一个属性constructor,它指向函数对象
(2)给原型对象添加属性(一般都是方法)
  • 作用:函数的所有实例对象自动拥有原型中的属性(方法)
//每个函数都有一个prototype属性,它默认指向一个Object空对象(原型对象)
console.log(Data.prototype, typeof Date.prototype) //...    object
function Fun {}
console.log(Fun.prototype) //默认指向一个Object空对象//原型对象中由一个属性constructor,它指向函数对象
console.log(Fun.prototype.constructor === Fun) //true
console.log(Date.prototype.constructor === Date) //true//给原型对象添加属性(一般是方法) ===> 实例对象可以访问
Fun.prototype.test = function() {console.log('test()')
}
var fun = new Fun()
fun.test() //test()

2、显示原型与隐式原型

(1)每个函数function都有一个prototype,即显示原型(属性)默认指向一个空的Object对象
(2)每个实例对象都有一个‘ _ _ proto _ _’,可称为隐式原型(属性)
(3)对象的隐式原型的值为其对应构造函数的显式原型的值
(4)内存构造(图)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W9wgJB0j-1650793106725)(C:\Users\hello world\AppData\Roaming\Typora\typora-user-images\1643186057444.png)]

function Fn() {//内部语句:this.prototype = {}
}//1、每个函数function都有一个prototype,即显示原型(属性)默认指向一个空的Object对象
console.log(Fn.prototype)
//2、每个实例对象都有一个__ proto__,可称为隐式原型(属性)
//创造实例对象
var fn = new Fn() //内部语句:this.__proto__ = Fn.prototype
//3、对象的隐式原型的值为其对应构造函数的显式原型的值
console.log(fn.__proto__ == Fn.prototype) // true//给原型添加方法
Fn.prototype.test = function() {console.log('test()')
}
fn.test() // test()
(5)总结
  • 函数的prototype属性:定义函数时自动添加的,默认值时一个空Object对象
  • 对象的_ _ proto _ _属性:创建对象时自动添加到,默认值为构造函数的prototype属性值
  • 程序员能直接操作显示原型,但不能直接操作隐式原型(ES6之前)

3、原型链

(1)原型链
  • 访问一个对象的属性值
    • 先在自身属性中查找,找到返回
    • 如果没有,再沿着 _ _ proto _ _ 这条链向上查找,找到返回
    • 如果最终没找到,返回underfined
  • 别名:隐式原型链
  • 作用:查找对象的属性(方法)

在这里插入图片描述

function Fn() {this.test1 = function() {console.log('test1()')}
}
Fn.prototype.test2 = function() {console.log('test1()')
}
var fn = new Fn()fn.test1()
fn.test2()
console.log(fn.toString())
fn.test3() //报错
(2)构造函数/原型实例对象的关系

在这里插入图片描述

(3)构造函数/原型实例对象的关系2

在这里插入图片描述

(4)相关问题
//1.函数的显示原型指向的对象默认时空Object实例对象(但Object不满足)
console.log(Fn.prototype instanceof Object) //true
console.log(Object.prototype instanceof Object) // false
console.log(Function.prototype instanceof Object) // true
//2.所有函数都是Function的实例(包含Function)
console.log(Function.__protp__ === Function.prototype) // true
//3.Object的原型对象是原型链尽头
console.log(Object.prototype.__proto__) //null

4、原型链属性问题

  1. 读取对象的属性值时:会自动到原型链中查找
  2. 设置对象的属性值时:不会查找原型链,如果当前对象中没有此属性,直接添加此属性并设置其值
  3. 方法一般定义在原型中,属性一般通过构造函数定义在对象本身上
function Fn() {}
Fn.prototype.a = 'xxx'
var fn1 = new Fn()
console.log(fn1.a, fn1) // xxxvar fn2 = new Fn()
fn2.a = 'yyy'
console.log(fn1.a,fn2.a,fn2) // xxx yyy function Person(name, age) {this.name = namethis.age = age
}
Person.prototype.setName = function(name) {this.name = name
}
var p1 = new Person('Tom', 12)
p1.setName('Bob')
console.log(p1) //Bob 12var p2 = new Person('jack', 12)
p2.setName('Cat')
console.log(p2) // Cat 12console.log(p1.__proto__ == p2.__proto__) // true 实例对象的隐式原型对象指向构造函数的显示原型对象

5、探索instanceof

1、instanceof是如何判断的?
  • 表达式:A instanceof B
  • 如果B函数的显示原型对象在A对象的原型链上,返回true,否则返回false
2、Function是通过new自己产生的实例
function Foo() {}
var f1 = new Foo()
console.log(f1 instanceof Foo) //true
console.log(f1 instanceof Obeject) // trueconsole.log(Object instanceof Function) //true
console.log(Object instanceof Object) //true
console.log(Function instanceof Function) //true
console.log(Function instanceof Object) //truefunction Foo(){}
console.log(Object instaenceof Foo) //false

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-968lJYs1-1650793106729)(C:\Users\hello world\AppData\Roaming\Typora\typora-user-images\1643304158857.png)]

6、面试题

//测试1
function A(){}
A.prototype.n = 1var b = new A()A.prototype = {n: 2,m: 3
}var c = new A()
console.log(b.n, b.m, c.n, c.m) // 1 undenfine 2 3//测试2
var F = function() {}
Object.prototype.a = function() {console.log('a()')
}
Function.prototype.b = function() {console.log('b()')
}
var f = new F()
f.a() //a()
f.b() //报错
F.a() //a()
F.b() //b()

二、执行上下文与执行上下文栈

1、变量提升与函数提升

(1)变量声明提升
  • 通过var定义(声明)的变量,在定义语句之前就可以访问到
  • 值:undefined
(2)函数声明提升
  • 通过function声明的函数,在之前就可以直接调用
  • 值:函数定义(对象)
var a = 3
function fn1() {console.log(a)var a = 4
}
fn1() //undenfine 变量提升,fn1函数相当于 var a; console.log(a); a = 4console.log(b) //undefined 变量提升
var b = 3fn2() //可调用 函数提升
function fn2() {console.log('fn2()')
}fn3() //不能 变量提升
var fn3 = function(){}

2、执行上下文

(1)代码分类(位置)
  • 全局代码
  • 函数(局部)代码
(2)全局执行上下文
  • 在执行全局代码前将window确定为全局执行上下文
  • 对全局数据进行预处理
    • var定义的全局变量 ==>underfined,添加为window的属性
    • function声明的全局函数 ==> 赋值(fun),添加为window的方法
    • this ==> 赋值(window)
(3)函数执行上下文
  • 在调用函数,准备执行函数体之前,创建对应的函数执行上下文对象
  • 对局部数据进行预处理
    • 形参变量 > 赋值(实参)> 添加为执行上下文的属性
    • argument ==>赋值(实参列表),添加为执行上下文的属性
    • var定义的局部变量 ==> undefined,添加为执行上下文的属性
    • function声明的函数 ==>赋值(fun),添加为执行上下文的方法
    • this ==> 赋值(调用函数的对象)
  • 开始执行函数体代码

3、执行上下文栈

(1)在全局代码执行前,JS引擎就会创建一个栈来存储管理所有的执行上下文对象
(2)在全局执行上下文(window)确定后,将其添加到栈中(压栈)
(3)在函数执行上下文创建后,将其添加到栈中(压栈)
(4)在当前函数执行完后,将栈顶的对象移除(出栈)
(5)当所有的代码执行完后,栈中只剩下window
//1.进入全局执行上下文
var a = 10
var bar = function (x) {var b = 5
//3.进入foo函数执行上下文 foo(x + b)
}
var foo = function (y) {var c== 5console.log(a + c + y)
}
//2.进入bar函数执行上下文 
bar(10) 

4、面试题

console.log('gb: '+i)
var i = 1
foo(1)
function foo(i) {if(i == 4) {return }console.log('fb: ' + i)foo(i + 1)console.log('fe: ' + i)
}
console.log('ge: ' + i)
//gb: undefine
//fb: 1
//fb: 2
//fb: 3
//fe: 3
//fe: 2
//fe: 1
//ge: 4
//执行上下文5个
//测试题1
function a() {}
var a;
console.log(typeof a)//测试题2
if(!(b in window)) {var b = 1
}
console.log(b) //undefine//测试题3
var c = 1
function c(c) {console.log(c)var c = 3
}
c(2) //报错,c不是一个函数
//其实代码相当于
var c
function c(c) {console.log(c)var c = 3
}
c = 1
c(2)

三、作用域与作用域链

1、作用域

(1)理解
  • 就是一块“地盘”,一个代码段所在区域
  • 它是静态的(相对于上下文对象),在编写代码时就确定
(2)分类
  • 全局作用域
  • 函数作用域
  • 没有块作用域(ES6有了)
(3)作用
  • 隔离变量,不用作用域下同名变量不会冲突

2、作用域与执行上下文

(1)区别1
  • 全局作用域之外,每个函数都会创建自己的作用域,作用域在函数定义时就已经确定了,而不是在函数调用时
  • 全局执行上下文环境是在全局作用域确定之后,js代码马上执行之前创建
  • 函数执行上下文环境是在调用函数时,函数体代码执行之前创建
(2)区别2
  • 作用域是静态的,只要函数定义好了就一直存在,且不会在变化
  • 上下文环境是动态的,调用函数时创建,函数调用结束时上下文环境就会被释放
(3)联系
  • 执行上下文(对象)是从属于所在的作用域
  • 全局上下文环境 ==>全局作用域
  • 函数上下文环境 ==> 对应的函数使用域

3、作用域链

(1)理解
  • 多个上下级关系的作用域形成的链,它的方向是从下向上的(从内到外)
  • 查找变量时就是沿着作用域链来查找的
(2)查找一个变量的查找规则
  • 在当前作用域下的执行上下文中查找对应的属性,如果有直接返回,否则进入2
  • 在上一级作用域的执行上下文中查找对应的属性,如果有直接返回,否则进入3
  • 再次执行2的相同操作,直到全局作用域,如果还找不到就抛出找不到的异常
var x = 10
function fn() {console.log(x)
}
function show(f) {var x = 20f()
}
show(fn)//10
var fn = function() {console.log(fn)
}
fn() //输出函数var obj = {fn2: function() {console.log(fn2) // 报错console.log(this.fn2) //正常输出函数}
}
obj.fn2()

四、闭包

1、理解闭包

(1)如何产生闭包
  • 当一个嵌套内部(子)函数引用了嵌套的外部(父)函数的变量(或函数)是,就产生了闭包
(2)闭包到底是什么
  • 理解1:闭包是嵌套的内部函数
  • 理解2:包含被引用变量(或函数)的对象
  • 注意:闭包存在于嵌套的内部函数中
function fn1() {var a = 2var b = 'abc'function fn2() { //执行函数定义就会产生闭包(不用调用内部函数)console.log(a)}fn2()
}
fn1() //需要调用外部函数
(3)产生闭包的条件
  • 函数嵌套
  • 内部函数引用了外部函数的数据(变量/函数)

2、常见闭包

//1.将函数作为另一个函数的返回值
function fn1() {var a = 2function fn2() {a++console.log(a)}return fn2 
}
var f = fn1() //执行外部函数
f() //3 执行内部函数
f() //4 执行内部函数//2.将函数作为实参传递给另一个函数调用
function showDelay(msg, time) {setTimeout(function() {alert(msg)},time)
}
showDelay('atguigu',2000)

3、闭包作用

(1)使用函数内部的变量在函数执行完后,仍然存活在内存中(延长了局部变量的声明周期)
(2)让函数外部可以操作(读写)到函数内部的数据(变量/函数)

问题:

(1)函数执行完后,函数内部声明的局部变量是否还存在?
  • 一般不存在,存在于闭包中的变量才存在
(2)在函数外部能直接访问函数内部的局部变量吗?
  • 不能,但我们可以通过闭包让外部操作它
//1.将函数作为另一个函数的返回值
function fn1() {var a = 2function fn2() {a++console.log(a)}return fn2 
}
var f = fn1() //执行外部函数 指向fn2,导致fn2不释放
f() //3 执行内部函数 
f() //4 执行内部函数

4、闭包生命周期

(1)产生:在嵌套内部函数定义执行完时就产生了(不是在调用)
(2)死亡:在嵌套的内部函数成为垃圾对象时
function fn1() {
//此时闭包就已经产生了(函数提升,内部函数对象已经创建了)var a = 2function fn2() {a++console.log(a)}//var fn2 = function () {// 	a++//  console.log(a)//} 闭包在此句完成才产生return fn2 
}
var f = fn1() //执行外部函数 指向fn2,导致fn2不释放
f() //3 执行内部函数 
f() //4 执行内部函数
f = null // 闭包死亡(包含闭包的函数对象成为垃圾对象)

5、闭包应用

闭包的应用:定义JS模块
  • 具有特定功能的js文件
  • 将所有的数据和功能封装在一个函数内部(私有的)
  • 只向外暴露一个包含n个方法的对象或函数
  • 模块的使用者,只需要通过模块暴露的对象调用方法来实现对应的功能
function myModule() {//私有数据var msg = 'My atguigu'//操作数据的函数function doSomething() {console.log('doSomething()' + msg.toUpperCase)}function doOtherting() {console.log('doOtherting()' + msg.toLowerCase)}//向外暴露对象(给外部使用的方法)return {doSomething: doSomething,doOtherthing:doOtherting}
}//
var module = myModule()
module.doSomething()
module.doOtherthing()
(function(window) {//私有数据var msg = 'My atguigu'//操作数据的函数function doSomething() {console.log('doSomething()' + msg.toUpperCase)}function doOtherting() {console.log('doOtherting()' + msg.toLowerCase)}//向外暴露对象(给外部使用的方法)window.myModule = {doSomething: doSomething,doOtherthing:doOtherting}
})(window)myModule.doSomething()
mymodule.doOtherthing()

6、闭包缺点

(1)缺点
  • 函数执行完后,函数内的局部变量没有释放,占用内存时间会变长
  • 容易造成内存泄漏
(2)解决
  • 能不用闭包就不用
  • 及时释放
function fn1(){var arr = new Array[10000]function fn2() {console.log(arr.length)}return fn2
}
var f = fn1()
f()
f = null//让内部函数成为垃圾对象 -->回收闭包 
(3)内存溢出
  • 一种程序运行出现的错误
  • 当程序运行需要的内存超过了剩余的内存时,就抛出内存溢出的错误
(4)内存泄漏
  • 占用的内存没有及时释放
  • 内存泄漏积累多了就容易导致内存溢出
  • 常见的内存泄露
    • 意外的全局变量
    • 没有及时清理的计时器或回调函数
    • 闭包
//意外的全局变量
function fn1() {a = new Array(1000)
}//没有及时清理的计时器或回调函数
var intervalId = setInterval(function(){ //启动循环定时器后不清理console.log('------') 
},1000)
//clearInterval(intervalId)//闭包
function fn1() {var a = 1;function fn2() {a++ console.log(a)}return fn2
}
var f = fn1()
f()
//f = null

五、面试题

var name1 = "the window"
var object1 = {name1: "my Object"getNameFunc: function() {//没有闭包return function() {return this.name}}
}
console.log(object1.getNameFunc()()) //the windowvar name2 = "the window"
var object1 = {name2: "my Object"getNameFunc: function() {var that = this // 闭包return function() {return that.name2}}
}
console.log(object2.getNameFunc()()) //my object
function fun(n,o) {console.log(o)return {fun: function(m){return fun(m,n) //  }}
}
var a = fun(0); a.fun(1); a.fun(2); a.fun(3) //undefine 0 0 0
var b = fun(0).fun(1).fun(2).fun(3); //undefine 0 1 2
var c = fun(0).fun(1); c.fun(2); c.fun(3); //undefine 0 1 1

【3】对象高级

一、对象创建模式

方式一:Object构造函数模式

  • 套路:先创建空Object对象,在动态添加属性/方法
  • 适用场景:起始时不确定对象内部数据
  • 问题:语句太多
var p = new Object()p.name = 'Tom'
p.age = 12
p.setName = function(name) {this.name = name
}

方式二:对象字面量模式

  • 套路:使用{}创建对象,同时指定属性/方法
  • 适用场景:起始时对象内部数据是确定的
  • 问题:如果创建多个对象,有重复代码
var p = {name: 'Tom',age: 12,setName: function(name) {this.name = name}
}

方式三:工厂模式

  • 套路:通过工厂函数动态创建对象并返回
  • 适用场景:需要创建多个对象
  • 问题:对象没有一个具体的类型,都是Object类型
function createPerson(name,age) {var obj = {name: name,age: age,setName: function(name) {this.name = name}}return obj
}
//创建
var p1 = createPerson('Tome',12)
var p1 = createPerson('BOb',12)
  • 方式四:自定义构造函数模式

  • 套路:自定义构造函数,通过new创建对象

  • 适用场景:需要创建多个类型确定的对象

  • 问题:每个对象都有相同的数据,浪费内存

function Person(name,age) {this.name = namethis.age = agethis.setName = function(name) {this.name = name}
}
function Student(name,age) {this.name = namethis.age = agethis.setName = function(name) {this.name = name}
}
var p = new Person('Tom',12)
var s = new Student('Jack',12)
console.log(p instanceof Person) // true
console.log(s instanceof Student) // true

二、继承模式

1、原型链继承

(1)套路
  • 定义父类型构造函数
  • 给父类的原型添加方法
  • 定义子类型的构造函数
  • 创建父类型的对象赋值给子类型的原型
  • 将子类型原型的构造属性设置为子类型
  • 给子类型原型添加方法
  • 创建子类型的对象:可以调用父类型的方法
(2)关键
  • 子类型的原型为父类型的一个实例对象
//父类型
function Supper() {this.supProp = 'Supper property'
}
Supper.prototype.showSupperProp = function() {console.log(this.supProp)
} 
//子类型
function Sub() {this.supProp = 'Sub property'
}
//子类型的原型为父类的一个实例对象
Sub.proeotype = new Supper()
//让子类型的原型的constructor指向SUb
Sub.proeotype.constructor = Sub
Sub.prototype.showSubProp = function() {console.log(this.supProp)
} 
var sub = new Sub() 
sub.showSupperProp() //Supper property'

在这里插入图片描述

2、借用构造函数继承(假的)

(1)套路
  • 定义父类型构造函数
  • 定义子类型的构造函数
  • 在子类型构造函数中调用父类型构造
(2)关键
  • 在子类型构造函数中通用supper()调用父类型构造函数
function Person(name, age) {this.name = namethis.age = age
}
function Student(name, age, price) {Person.call(this,name, age) //相当于:this.Preson(name, age)this.price = price
}
var s = new Student('Jack', 12, 14000)

3、组合继承

(1)原型链+借用构造函数的组合继承
  • 利用原型链实现对父类型对象的方法继承
  • 利用super()借用父类型构建函数初始化相同属性
function Person(name, age) {this.name = namethis.age = age
}
Person.prototype.setName = function (name) {this.name = name
}
function Student(name, age, price) {Person.call(this,name, age) //为了得到属性this.price = price
}
Student.prototype = new Person() //为了看见父类型的方法
Student.prototype.constructor = Student //修正constructor属性
Student.prototype.setPrice = {this.price = price
}
var s = new Student('Jack', 12, 14000)

【4】线程机制与事件机制

一、进程与进程

1、进程

  • 程序的一次执行,它占有一片独有的内存空间
  • 可以通过windows任务管理查看进程
2、线程
  • 是进程内的一个独立执行单元
  • 是程序执行的一个完整流程
  • 是CPU的最小调度单元

3、图解

在这里插入图片描述

4、相关知识

  • 应用程序必须运行在某个进程的某个线程上
  • 一个进程中至少有有一个运行的线程:主线程,进程启动后自动创建
  • 一个进程中也可以同时运行多个线程,我们会说程序是多线程运行的
  • 一个进程内的数据可以供其中的多个线程直接共享
  • 多个进程之间的数据是不能直接共享的
  • 线程池(thread pool):保存多个线程对象的容器,实现线程对象的反复利用

5、相关问题

(1)何为多进程与多线程
  • 多进程运行:一应用层序可以同时启动多个实例运行
  • 多线程:在一个进程内,同时有多个线程运行
(2)JS是单线程还是多线程
  • js是单线程运行的
  • 但使用H5中的Web Workers可以多线程运行
(3)比较单线程与多线程
  • 多线程
    • 优点
      • 能有效提升CPU的利用率
    • 缺点
      • 创建多线程开销
      • 线程间切换开销
      • 死锁与状态同步问题
  • 单线程
    • 优点
      • 顺序编程简单易懂
    • 缺点
      • 效率低
(4)浏览器运行是单线程还是多线程

有的单线程有的多线程

  • 单:firefox、老版IE
  • 多:chrome、新版IE

二、浏览器内核

支持浏览器运行的最核心的程序

三、定时器引发的思考

1、定时器真的是定时执行的吗?

  • 定时器并不能保证真正定时执行
  • 一般会延时一点(可以接收),也有可能延迟很长时间(不能接收)

2、定时器回调函数是在哪个线程执行的?

  • 在主线程执行的,js是单线程的

3、定时器是如何实现的?

  • 事件循环模型

四、JS是单线程执行

五、浏览器的事件循环(轮询)模型

[外链图片转存中...(img-BEBpVOUC-1650793106731)]


http://chatgpt.dhexx.cn/article/GuAPK92n.shtml

相关文章

Mybatis-plus (教程来自尚硅谷视频)

1.什么是Mybatis-plus? 官网地址:MyBatis-Plus 1.1MyBatis-Plus(简称 MP)是一个 MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。 Mybatis-plus的愿景成为Mybatis的最好拍档&a…

JavaSE(尚硅谷视频学习笔记)

文章目录 Java基础编程Java语言概述Java语言简述1.基础图解2.常识3.计算机语言的发展迭代4.Java语言版本迭代概述5. Java语言应用的领域6.Java语言的特点 开发环境的搭建1. JDK、JRE、JVM的关系2. JDK的下载安装 注释与API文档1. 注释Comment2. Java API 文档3. 良好的编程风格…

尚硅谷Java入门视频教程(一)编程入门

冯诺依曼体系结构:中央处理器(CPU)(寄存器、算术逻辑单元、控制单元)、内存(主存)、存储设备(内存、硬盘)、输入输出设(外设、显示器)、通信设备(网卡等)。通过总线连接,传输数据。 中央处理器:(Central Processing Unit CPU):获…

尚硅谷Java入门视频教程第五章——面向对象编程(中)

尚硅谷Java入门视频教程第五章——面向对象编程(中) 第5章:面向对象编程(中)5.1 面向对象特征之二:继承性5.2 方法的重写(override/overwrite)5.3 四种访问权限修饰符5.4 关键字:super5.5 子类对…

“为了对电脑进行保护,已经阻止此应用。”

环境:Win10专业版 解决方法:

win10运行安装软件程序提示“为了对电脑进行保护,已经阻止此应用” 有效解决方法记录

问题: 解决: 在程序文件上,按住【shift】键,同时点击鼠标右键→【复制为路径】,打开C:\Windows\System32,找到cmd.exe,右键→【以管理员身份运行】,在打开的界面将路径粘贴&#xff…

【windows】Windows10为了对电脑进行保护,已经阻止此应用解决方案

winr打开运行输入“gpedit.msc”,打开“本地组策略编辑器”,依次点开: 1.计算机配置 2.Windows设置 3.安全设置 4.本地策略 5.安全选项 在右边框内找到并双击“用户账户控制:以管理员批准模式运行所有管理员” 在打开的对话框中选择“…

为了对电脑进行保护,已经阻止此应用 解决办法

上面就是问题,这个是我在安装百度硬盘搜索的时候出现的,不知道啥原因。在网上找了一堆的解决方法都没有成功,比如修改本地策略,修改安全级别等等。最后发现一个人的方法有效分享给大家: 1.用管理员身份执行cmd 2.复制该…

Win10提示“为了对电脑进行保护,已经阻止此应用”如何解决

Win10提示“为了对电脑进行保护,已经阻止此应用”如何解决 从Win7系统升级到Win10正式版系统后,发现其他目录的一些程序都无法打开,且提示“为了对电脑进行保护,已经阻止此应用”,这是怎么回事呢?其实,该问…

Win10家庭版安装软件时提示“为了对电脑进行保护,已经阻止此应用”

如果你遇到了这个问题 你也是Win10家庭版,则下面的方法拯救不了你: 第一步: 恢复组策略 在桌面新建文本文档,粘贴代码: echo off pushd “%~dp0” dir /b C:\Windows\servicing\Packages\Microsoft-Windows-Group…

为了保护您的计算机,windows已经关闭了此程序,电脑Win7升级Win10系统后运行程序提示为了对电脑进行保护已经阻止此应用的解决方法...

随着我国互联网技术不断的进步,计算机网络的发展也逐渐趋向成熟。计算机网络发展为人民群众生活带来了很大的益处,使得人们的生活更便捷与信息化。下面是学习啦小编为大家整理的关于电脑Win7升级Win10系统后运行程序提示为了对电脑进行保护已经阻止此应用的解决方法&#xff0c…

2021-01-29-Windows10系统专业版-右键计算机管理,弹出警告框:为了对电脑进行保护,已阻止此应用。 管理员已阻止你运行此应用。有关详细信息,请与管理员联系。完美解决方案

1、按windows按钮,输入cmd,有一个以管理员身份运行的命令,点击打开 1.1、如果找不到,可以试试这个路径:C:\Users\Administrator\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\System Tools,里面…

你的账户配置为阻止使用计算机,Win10提示“为了对电脑进行保护,已经阻止此应用”如何解决-系统城...

从Win7系统升级到Win10正式版系统后,发现其他目录的一些程序都无法打开,且提示“为了对电脑进行保护,已经阻止此应用”,这是怎么回事呢?其实,该问题是由于系统所登录的账号管理权限不足导致的。下面&#x…

你的账户配置为阻止使用计算机,win10运行程序提示“为了对电脑进行保护,已经阻止此应用”怎么办...

升级win10系统之后,有用户在安装软件程序时提示“为了对电脑进行保护,已经阻止此应用”,“管理员已阻止你运行此应用。发布者:不受信任”,这是怎么回事呢?其实这是win10系统的帐户安全控制机制,…

win10运行程序提示“为了对电脑进行保护,已经阻止此应用” 解决方法

升级win10系统之后,有用户在安装软件程序时提示“为了对电脑进行保护,已经阻止此应用”,“管理员已阻止你运行此应用。发布者:不受信任”,这是怎么回事呢?其实这是win10系统的帐户安全控制机制,…

为了对计算机的保护你的管理员已阻止你运行此程序,Win 10系统提示:为了对电脑进行保护 已经阻止此应用 怎么办?...

Win10 系统运行某个软件时提示“用户账号控制”,“为了对电脑进行保护,已经阻止此应用”,“管理员已阻止你运行此应用。有关详细信息,请于管理员联系”。 之前也碰到几次也按照网上的方法启用“用户账户控制:以管理员批…

你的账户配置为阻止使用计算机,Win10打开软件提示为了对电脑进行保护,已经阻止此应用解决方法...

近期有网友遇到一个问题,那就是在Windows10系统中打开或者安装软件的时候用户账户控制提示了“为了对电脑进行保护,已经阻止此应用”的问题,不知道如何解决该问题。针对这个问题,装机之家分享了Win10打开软件提示"为了…

Window异常提示:“为了对电脑进行保护,已经阻止此应用”

目录 1.Window异常提示图片: 2.家庭版额外需要执行的解决方式: 3.本地组策略编辑器(后续家庭版和专业版一致) 4.禁用后重新启动电脑就可以正常运行程序了 1.Window异常提示图片: 2.家庭版额外需要执行的解决方式: 代码&#xff…

win10 安装程序显示“为了对电脑进行保护,已经阻止此应用” 管理员已阻止你运行此应用

现象如下图所示: 解决方法如下: 1、“winx”进入控制面板,选择安全性与维护,在左侧更改windows smartscreen筛选器设置,选择"不执行任何操作",单击确定即可。 2、“winx”进入控制面板&#xff0…

Windows10安装打开软件提示“为了对电脑进行保护,已经阻止此应用”解决方法!

下载好了却安装不上? 在Windows10系统中打开或者安装部分软件的时候用户账户控制提示了“为了对电脑进行保护,已经阻止此应用”。 解决方法 1.按下WinR“”组合快捷键打开“运行”,在运行中输入“gpedit.msc”并确定即可打开组策略编辑器。…