彼方尚有荣光在|

_xiaolin

园龄:2年9个月粉丝:3关注:5

javaScript高级

js高级

[Toc]

一、基础总结深入

1、数据类型1

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>01_数据类型</title>
</head>
<body>
<!--
1. 分类
    基本(值)类型
        -String:任意字符串
        -Number:任意数字
        -boolean:true false
        -undefined:undefined
        -null:null
    对象(引用)类型
        -Object:任意对象
            -Fucition:一种特别的对象(可以执行)
            -Array:一种特别的对象(数值下标,内部数据是有序的)
2. 判断
    1、typeof
        -可以判断undefined,数值,字符串,布尔值,function
        -不能判断null和Object,Object和array
    2、instanceof
        -判断对象的具体类型
    3、===
        -可以判断undefined,null
    
-->

<script type="text/javascript"> // 1、基本
    var a;
    console.log(a,typeof a,typeof a==='undefined',a===undefined);//undefined 'undefined' true true
    console.log(undefined==='undefined');//false

    a=3;
    console.log(typeof a==='number' );//true

    a='xiaolin';
    console.log(typeof a==='string');//true

    a=true;
    console.log(typeof a==='boolean');//true

    a=null;
    console.log(typeof a,a===null);//object,true
    
    console.log('=====================');

    var b1={
        b2:[1,"abc",console.log],
        b3:function(){
            console.log('b3');
            return function(){
                return 'xiaolin';
            }
        }
    };

    console.log(b1 instanceof Object,b1 instanceof Array);//true false 
    console.log(b1.b2 instanceof Array,b1.b2 instanceof Object);//true true
    console.log(b1.b3 instanceof Function,b1.b3 instanceof Object);//true true

    console.log(typeof b1.b2);//object

    console.log(typeof b1.b3,typeof b1.b3==='function');// 'fucction' true

    console.log(typeof b1.b2[2]==='function');//true
    b1.b2[2](4);//4
    console.log(b1.b3()());//xiaolin

    b1.b3();//b3

    /* var obj = {
        name:"Tom",
        age:18
    };
    function test(){
        var a=3;
    }
    var arr=[3,"abc"]; */
    // alert(arr[1]); </script>
</body>
</html> 

2、数据类型2

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>01_相关问题</title>
</head>
<body>
<!--
1. undefined与null的区别?
    -undefined代表定义了未赋值
    -null代表定义并赋值了,只是值为null
2. 什么时候给变量赋值为null呢?
    -初始赋值,表明将要赋值为对象
    -结束前赋值为null,让其成为垃圾对象(被垃圾回收器回收)
3. 严格区别变量类型与数据类型?
    -数据的类型
        1、基本类型
        2、对象类型

    -变量的类型(变量内存值的类型)
        -基本类型:保存的就是基本类型的数据
        -引用类型:保存的是地址值
-->

<script type="text/javascript"> //实例:实例对象
    // 类型:类型对象
    function Person(name,age){ //构造函数 类型
        this.name=name;
        this.age=age;
    }
    var p = new Person('tom',18);//根据类型创建的实例对象
    // Person('jack',12);//合法但不合理

    //1. undefined与null的区别?
    var a;
    console.log(a);//undefined
    a=null;
    console.log(a);//null

    var b=null;//初始赋值为null,表明将要赋值为对象
    //确定对象就赋值
    b = ['xiaolin',18];
    // 最后
    b=null;//切断指向对象的线,后会成为垃圾对象被回收期自动回收
    // b=2;

    var c=function(){

    };
    console.log(typeof c);//'function' </script>
</body>
</html> 

3、数据、变量和内存1

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>02_数据_变量_内存</title>
</head>
<body>
<!--
1. 什么是数据?
    -存储在内存中代表特定信息的东西,本质上是0101...
    -数据的特点:可传递,可运算
    -一切皆数据
    -内存中所有操作的目标:数据
        -算数运算
        -逻辑运算
        -赋值运算
        -运行函数
2. 什么是内存?
    -内存条通电以后产生的可存储数据的空间(临时的)
    -内存产生和死亡:内存条(电路板)==>通电==>产生内存空间==>存储数据==>处理数据==>断电==>内存空间和数据都消失
    -一块小内存的2个数据
        -内存存储的数据
        -地址值
    -内存分类
        -栈内存:全局变量和局部变量
        -堆内存:对象
3. 什么是变量?
    -可变化的量,由变量名和变量值组成
    -每个变量都对应一块小内存,变量名用来查找对应的内存,变量值就是内存中保存的数据
4. 内存,数据, 变量三者之间的关系
    -内存是用来存储数据的空间
    -变量是内存的标识
-->
<script type="text/javascript"> var age=18;
    var a =2;
    var obj = {
        name:'tom'
    };
    console.log(obj.name);

    function fn(){
        var obj ={name:'tom'};
    }


    var a =3;
    var b=a+2; </script>
</body>
</html> 

4、数据、变量和内存2

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>关于赋值和内存的问题</title>
</head>
<body>
<!--
  问题: var a = xxx, a内存中到底保存的是什么?
    xxx是基本数据,保存的就是这个基本数据
    xxx是对象,保存的就是对象的地址值
    xxx是变量,保存的xxx的内存内容(可能是基本数据,也可能是地址值)
    
-->
<script type="text/javascript"> var a = 3;
    var a =function(){

    };
    var b="abc";
    a=b;
    b={}
    a=b </script>
</body>
</html> 

5、数据、变量和内存3

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>02_关于引用变量赋值问题</title>
</head>
<body>
<!--
关于引用变量赋值问题
    多个引用变量指向同一个对象,通过其中一个变量修改对象内部数据
    其他所有变量看到的是修改之后的数据

    两个引用变量指向同一个对象,现在让其中一个引用变量指向另一个对象,另一个引用
    变量仍然指向原来的对象,此时两个引用变量互不相关

-->
<script type="text/javascript"> var obj1={name:'tom'};
    var obj2=obj1;
    obj1.name='jack';
    console.log(obj2.name);//'jack'
    function fun(obj){
        obj.name='bob';
    }

    fun(obj1);
    console.log(obj2.name);//bob

    var a = {age:12};
    var b = a;
    a = {name:'bob',age:13};//a断开原来的连接,指向新创建的一个对象了
    console.log(b);//指向原来a指向的对象
    b.age=14;
    console.log(b.age,a.name,a.age);//14 bob 13

    function fun2(obj){
        obj = {age:15};
    }

    fun2(a);
    console.log(a.age);//13 </script>
</body>
</html> 

image-20221029143431459

6、数据变量和内存4

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>02_关于数据传递问题</title>
</head>
<body>
<!--
问题: 在js调用函数时传递变量参数时, 是值传递还是引用传递
    理解1:都是值(基本数据/地址值)传递
    理解2:可能是值传递,也可能是引用传递(地址值)
-->
<script type="text/javascript"> var a=3;
    function fn(a){
        a=a+1;
    }
    fn(a);
    console.log(a);//3

    function fn2(obj){
        console.log(obj.name);
    }
    var obj={name:'tom'};
    fn2(obj); </script>
</body>
</html> 

7、数据、变量和内存5

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>02_内存管理</title>
</head>
<body>
<!--
问题: JS引擎如何管理内存?
1. 内存生命周期
    -分配小内存空间,得到它的使用权
    -存储数据,可以反复进行操作
    -释放当前的小内存空间
2. 释放内存
    -局部变量:函数执行完自动释放
    -对象:成为垃圾对象==>垃圾回收器自动回收
-->
<script type="text/javascript"> var a=3;
    var obj = {};
    obj=null;

    function fn(){
        var b ={};
    }

    fn();//执行完,b自动释放,b所指向的对象是在后面的某个时刻由垃圾回收器回收的 </script>
</body>
</html> 

8、对象1

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>03_对象</title>
</head>
<body>
<!--
1. 什么是对象?
    -多个数据的封装体
    -用来保存多个数据的容器
    -一个对象代表现实中的一个事物

2. 为什么要用对象?
    -统一管理多个数据

3. 对象的组成
    -属性:属性名(字符串)和属性值(任意类型)组成
    -方法:一种特别的属性(属性值是函数)

4. 如何访问对象内部数据?
    -对象.属性名:编码简单,有时不能用
    -对象['属性名']:编码麻烦,但是里面可以放变量,通用

-->
<script type="text/javascript"> var tom = {
        name:'tom',
        age:18,
        setName:function(name){
            this.name=name;
        },
        setAge:function(age){
            this.age=age;
        }
    };

/*     var name='tom';
    var age = 18; */
    tom.setName('bob');
    tom['setAge'](23);
    console.log(tom.name,tom['age']); </script>
</body>
</html> 

9、对象2

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>03_相关问题</title>
</head>
<body>
<!--
问题: 什么时候必须使用['属性名']的方式?
    1、属性名包含特殊字符: - 空格
    2、属性名不确定
-->
<script type="text/javascript"> var p ={};
    // 1、给p对象添加一个属性:content-type:text/json
    // p.content-type:'text/json';
    p['content-type']='text/json';
    console.log(p['content-type']);

    // 2、属性名不确定
    var propName = 'myAge';
    var value = 18;
    
    // p.propName = value;//这样存储的属性名是propName
    // console.log(p);

    p[propName]=value;
    console.log(p[propName]);//18 </script>
</body>
</html> 

10、函数

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>04_函数</title>
</head>
<body>
<!--
1. 什么是函数?
    -实现特定功能的n条语句的封装体
    -只有函数是可以执行的,其他类型的数据不能执行
2. 为什么要用函数?
    -提高代码复用
    -便于阅读交流
    
3. 如何定义函数?
    -函数声明
    -表达式
4. 如何调用(执行)函数?
    -test():直接调用
    -obj.test():通过对象调用
    -new test():new调用
    -test.call/apply(obj);//临时让test成为obj的方法被调用
-->
<script type="text/javascript"> /*
  编写程序实现以下功能需求:
    1. 根据年龄输出对应的信息
    2. 如果小于18, 输出: 未成年, 再等等!
    3. 如果大于60, 输出: 算了吧!
    4. 其它, 输出: 刚好!
  */
    function showInfo(age){
        if(age<18){
            console.log("未成年,再等等!");
        }else if(age>60){
            console.log("算了吧");
        }else{
            console.log('刚好');
        }
    }

    showInfo(17);
    showInfo(20);
    showInfo(65);


    function fn1(){//函数声明
        console.log('fn1()');
    }

    var fn2 = function(){ //表达式
        console.log('fn2()');
    }

    fn1();
    fn2();

    var obj={};
    function test2(){
        this.name ='xiaolin';
    }

    test2.call(obj);//obj.test2();//可以让一个函数成为指定任意对象的方法进行调用
    console.log(obj.name);//xiaolin </script>
</body>
</html> 

11、回调函数

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>05_回调函数</title>
</head>
<body>
<button id="btn">测试点击事件</button>
<!--
1. 什么函数才是回调函数?
    -你定义的
    -你没有调用
    -但最终它执行了(在特殊条件或时刻)
2. 常见的回调函数?
    -dom事件回调函数
    -定时器回调函数
    -ajax请求回调函数
    生命周期回调函数

-->
<script type="text/javascript"> var btn=document.getElementById("btn");
    btn.onclick=function(){//dom事件回调函数
        alert(this.innerHTML);
    }


    // 定时器
        // 超时定时器
        // 循环定时器
    setTimeout(function(){//定时器回调函数
        alert('到点了');
    },2000); </script>

</body>
</html> 

12、IFFE立即执行函数

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>06_IIFE</title>
</head>
<body>
<!--
1. 理解
  * 全称: Immediately-Invoked Function Expression
  立即执行函数
2. 作用
    -隐藏实现
    -不会污染外部(全局)命名空间
    -用它来编写js模块
-->
<script type="text/javascript"> (function (){ //匿名函数自调用
        // console.log('......');
        var a =3;
        console.log(a+3);
    })();
    var a =4;
    console.log(a);


    (function (){ 
        var a=1;

        function test(){
            console.log(++a);
        }

        function test2(){
            console.log('test2');
        }

        window.$=function(){ //向外暴漏一个函数
            return  {
                test:test
            }
       }
    })();


    console.log(typeof $()==='function');
    $().test();//1、$是一个函数,2、$执行后返回的是一个对象 </script>

</body>
</html> 

13、函数中的this

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>07_函数中的this</title>
</head>
<body>
<!--
1. this是什么?
  * 任何函数本质上都是通过某个对象来调用的,如果没有直接指定就是window
  * 所有函数内部都有一个变量this
  * 它的值是调用函数的当前对象
2. 如何确定this的值?
  * test(): window
  * p.test(): p
  * new test(): 新创建的对象
  * p.call(obj): obj
-->

<script type="text/javascript"> function Person(color) {
    console.log(this);
    this.color = color;
    this.getColor = function () {
      console.log(this);
      return this.color;
    };
    this.setColor = function (color) {
      console.log(this);
      this.color = color;
    };
  }

  Person("red"); //this是谁? window

  var p = new Person("yellow"); //this是谁? p

  p.getColor(); //this是谁? p

  var obj = {};
  p.setColor.call(obj, "black"); //this是谁? obj

  var test = p.setColor;
  test(); //this是谁? window

  function fun1() {
    function fun2() {
      console.log(this);
    }

    fun2(); //this是谁? window
  }
  
  fun1(); </script>
</body>
</html> 

14、分号问题

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>01_分号问题</title>
</head>
<body>

<!--
1. js一条语句的后面可以不加分号
2. 是否加分号是编码风格问题, 没有应该不应该,只有你自己喜欢不喜欢
3. 在下面2种情况下不加分号会有问题
  * 小括号开头的前一条语句
  * 中方括号开头的前一条语句
4. 解决办法: 在行首加分号
5. 强有力的例子: vue.js库
6. 知乎热议: https://www.zhihu.com/question/20298345
-->
<script type="text/javascript"> var a = 3
  ;(function () {

  })()
  /*
   错误理解
   var a = 3(function () {

   })();
  */

  var b = 4
  ;[1, 3].forEach(function () {

  })
  /*
  错误理解
   var b = 4[3].forEach(function () {

   })
   */ </script>
</body>
</html> 

二、函数高级

1、原型与原型链

1、原型--prototype

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>01_原型(prototype)</title>
</head>
<body>
<!--
1. 函数的prototype属性(图)
  * 每个函数都有一个prototype属性, 它默认指向一个Object空对象(即称为: 原型对象)
  * 原型对象中有一个属性constructor, 它指向函数对象
2. 给原型对象添加属性(一般都是方法)
  * 作用: 函数的所有实例对象自动拥有原型中的属性(方法)
-->
<script type="text/javascript"> console.log(Date.prototype,typeof Date.prototype);//Object
    function Fun(){

    }
    

    console.log(Fun.prototype);//默认指向一个object空对象(没有我们的属性)
    
  
    //原型对象中有一个属性constructor, 它指向函数对象
    console.log(Date.prototype.construtor===Date);//true
    console.log(Fun.prototype.construtor===Fun);//true

    // 给原型对象添加了属性(一般是属性)==>实例对象可以访问
    Fun.prototype.test=function(){
        console.log('test()');
    }

    var fun = new Fun();
    fun.test(); </script>
</body>
</html> 

2、显示原型和隐式原型

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>02_显式原型与隐式原型</title>
</head>
<body>
<!--
1. 每个函数function都有一个prototype,即显式原型
2. 每个实例对象都有一个__proto__,可称为隐式原型
3. 对象的隐式原型的值为其对应构造函数的显式原型的值
4. 内存结构(图)
5. 总结:
  * 函数的prototype属性: 在定义函数时自动添加的, 默认值是一个空Object对象
  * 对象的__proto__属性: 创建对象时自动添加的, 默认值为构造函数的prototype属性值
  * 程序员能直接操作显式原型, 但不能直接操作隐式原型(ES6之前)
-->
<script type="text/javascript"> // 定义构造函数
    function Fn(){ //内部语句:this.prototype={}

    }

    //1. 每个函数function都有一个prototype,即显式原型属性,,默认指向一个空的object对象
    console.log(Fn.prototype);
    //2. 每个实例对象都有一个__proto__,可称为隐式原型
    //创建实例对象
    var fn =  new Fn();//内部语句:fn.__proto__ = Fn.prototype;
    console.log(fn.__proto__);
    //3. 对象的隐式原型的值为其对应构造函数的显式原型的值
    console.log(Fn.prototype===fn.__proto__);//true
    //给原型添加方法
    Fn.prototype.test=function(){
        console.log('test()');
    };

    //通过实例调用原型的方法
    fn.test(); </script>
</body>
</html> 

3、原型链

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>03_原型链</title>
</head>
<body>
<!--
1. 原型链(图解)
  * 访问一个对象的属性时,
    * 先在自身属性中查找,找到返回
    * 如果没有, 再沿着__proto__这条链向上查找, 找到返回
    * 如果最终没找到, 返回undefined
  * 别名: 隐式原型链
  * 作用: 查找对象的属性(方法)
2. 构造函数/原型/实体对象的关系(图解)
3. 构造函数/原型/实体对象的关系2(图解)
-->
<script type="text/javascript"> // console.log(Object);
    // console.log(Object.prototype);

    console.log(Object.prototype.__proto__);//null
    

    function Fn(){
        this.test1=function(){
            console.log('test1()');
        }
    }
    console.log(Fn.prototype);

    Fn.prototype.test2=function(){
        console.log('test2()');
    }

    // console.log(Fn.prototype);

    var fn=new Fn();

    fn.test1();
    fn.test2();
    console.log(fn.toString());
    console.log(fn.test3);//undefined
    fn.test3();


    /* 
        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的实例(包括它本身)
    */
    console.log(Function.__proto__===Function.prototype);
    /* 
        3、Object的原型对象是原型链的尽头
    */
    console.log(Object.prototype.__proto__);//null </script>
</body>
</html> 

image-20221030001846560

image-20221030004117760

4、原型链--属性问题

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>04_原型链_属性问题</title>
</head>
<body>
<!--
1. 读取对象的属性值时: 会自动到原型链中查找
2. 设置对象的属性值时: 不会查找原型链, 如果当前对象中没有此属性, 直接添加此属性并设置其值
3. 方法一般定义在原型中, 属性一般通过构造函数定义在对象本身上
-->
<script type="text/javascript"> function Fn(){

    }
    Fn.prototype.a ="xxx";
    var fn1=new Fn();
    console.log(fn1.a,fn1);

    var fn2=new Fn();
    fn2.a='yyy';//在fn2自身定义了一个属性
    console.log(fn1.a);//xxx
    console.log(fn2.a,fn2);//yyy

    function Person(name,age){
        this.name=name;
        this.age=age;
    }
    Person.prototype.setName=function(name){
        this.name=name;
    }
    var p1 = new Person('tom',12);
    p1.setName('bob');
    console.log(p1);

    var p2 = new Person('jack',12);
    p1.setName('lili');
    console.log(p2); </script>
</body>
</html> 

5、探索instanceof

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>05_探索instanceof</title>
</head>
<body>
<!--
1. instanceof是如何判断的?
  * 表达式: A instanceof B
  * 如果B函数的显式原型对象在A对象的原型链上, 返回true, 否则返回false
2. Function是通过new自己产生的实例
-->
<script type="text/javascript"> /* 
        案例1
    */
    function Foo(){

    }
    var f1=new Foo();
    console.log(f1 instanceof Foo);//true
    console.log(f1 instanceof Object);//true

    /* 
        案例2
    */
    console.log(Object instanceof Function);//true
    console.log(Object instanceof Object);//true
    console.log(Function instanceof Function);//true
    console.log(Function instanceof Object);//true
    
    function Foo(){}
    console.log(Object instanceof Foo);//false </script>
</body>
</html> 

6、面试题

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>06_面试题</title>
</head>
<body>

<script type="text/javascript"> /*
  测试题1
   */
  var A = function() {

  }
  A.prototype.n = 1;

  var b = new A();

  A.prototype = {
    n: 2,
    m: 3
  }

  var c = new A();
  console.log(b.n, b.m, c.n, c.m);//1,undefined,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();//找到Object.prototype,输出a()
//   f.b();//找不到,报错not a function
  F.a();//找到Object.prototype,输出a()
  F.b();//找到Function.prototype,输出b()

  console.log(Object.prototype);
  console.log(Function.prototype); </script>
</body>
</html> 

image-20221030105347410

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

1、变量提升与函数提升

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>01_变量提升与函数提升</title>
</head>
<body>
<!--
1. 变量声明提升
  * 通过var定义(声明)的变量, 在定义语句之前就可以访问到
  * 值: undefined
2. 函数声明提升
  * 通过function声明的函数, 在之前就可以直接调用
  * 值: 函数定义(对象)
3. 问题: 变量提升和函数提升是如何产生的?
-->
<script type="text/javascript"> /* 
        面试题:输出undefined
    */
    var a=3;
    function fn(){
        console.log(a);
        var a =4;
    }
    /* 
        上面函数等同于
    */
    /* function fn(){
        var a ;
        console.log(a);
        a=4;
    } */
    fn();//因为,局部变量提升,先声明了,所以不找全局变量的a,但此时未赋值,所以输出undefined

    fn2();//可调用,函数提升
    fn3();//不能调用,变量提升,认为fn3是变量,而不是一个函数,会报错

    function fn2(){
        console.log('fn2()');
    }


    var fn3 =function(){
        console.log('fn3()');
    } </script>
</body>
</html> 

2、执行上下文

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>02_执行上下文</title>
</head>
<body>
<!--
1. 代码分类(位置)
  * 全局代码
  * 函数代码
2. 全局执行上下文
  * 在执行全局代码前将window确定为全局执行上下文
  * 对全局数据进行预处理
    * var定义的全局变量==>undefined, 添加为window的属性
    * function声明的全局函数==>赋值(fun), 添加为window的方法
    * this==>赋值(window)
  * 开始执行全局代码
3. 函数执行上下文
  * 在调用函数, 准备执行函数体之前, 创建对应的函数执行上下文对象(虚拟的,存在于栈中)
  * 对局部数据进行预处理
    * 形参变量==>赋值(实参)==>添加为执行上下文的属性
    * arguments==>赋值(实参列表), 添加为执行上下文的属性
    * var定义的局部变量==>undefined, 添加为执行上下文的属性
    * function声明的函数 ==>赋值(fun), 添加为执行上下文的方法
    * this==>赋值(调用函数的对象)
  * 开始执行函数体代码
-->
<script type="text/javascript"> // 全局执行上下文
    console.log(a1,window.a1);
    a2();
    console.log(this);
    var a1=3;
    function a2(){
        console.log('a2()');
    }
    console.log(a1);

    console.log("===========");

    //函数执行上下文
    function fn(a1){
        console.log(a1);//2
        console.log(a2);//undefined
        a3();//a3()
        console.log(this);//window
        console.log(arguments);//伪数组(2,3)
        var a2=3;
        function a3(){
            console.log('a3()');
        }
    }

    fn(2,3); </script>
</body>
</html> 

3、执行上下文栈

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>03_执行上下文栈</title>
</head>
<body>
<!--
1. 在全局代码执行前, JS引擎就会创建一个栈来存储管理所有的执行上下文对象
2. 在全局执行上下文(window)确定后, 将其添加到栈中(压栈)
3. 在函数执行上下文创建后, 将其添加到栈中(压栈)
4. 在当前函数执行完后,将栈顶的对象移除(出栈)
5. 当所有的代码执行完后, 栈中只剩下window
-->
<script type="text/javascript"> var a=10;
    var bar = function(x){
        var b=5;
        foo(x+b);
    }
    var foo=function(y){
        var c=5;
        console.log(a+c+y);
    }
    bar(10);//
    bar(10); </script>
  
</body>
</html> 

image-20221030121023375

4、执行上下文栈2

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>04_执行上下文栈2</title>
</head>
<body>
<!--
1. 依次输出什么?
    gb:undefined
    ge:1
    fb:1
    fb:2
    fb:3
    fe:3
    fe:2
    fe:1
2. 整个过程中产生了几个执行上下文?
    5个
-->
<script type="text/javascript"> console.log('global begin:'+i);//undefined
    var i=1;
    foo(1);
    function foo(i){
        if(i==4){
            return;
        }
        console.log('foo() begin:'+i);
        foo(i+1);//递归调用
        console.log("foo() end:"+i);
    }
    console.log("global end:"+i);//1 </script>

</body>
</html> 

image-20221030123506158

5、面试题

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>05_面试题</title>
</head>
<body>
<script type="text/javascript"> /* 
        测试题1:先执行变量提升,再执行函数提升?
        函数提升优先级高于变量提升,且不会被同名变量声明覆盖,但是会被变量赋值后覆盖。而且存在同名函数与同名变量时,优先执行函数。
    */
    function a(){}
    var a;
    console.log(typeof a);//function

    /* 
        测试题2
    */
    if(!(b in window)){
        var b=1;
    }
    console.log(b);//undefined

    /* 
        测试题3
    */
    var c=1;
    function c(c){
        console.log(c);
    }

    /* var c;
    function c(c){
        console.log(c);
    }
    c=1; */
    c(2);//报错,not a function </script>
</body>
</html> 

3、作用域和作用域链

1、作用域

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>01_作用域</title>
</head>
<body>
<!--
1. 理解
  * 就是一块"地盘", 一个代码段所在的区域
  * 它是静态的(相对于上下文对象), 在编写代码时就确定了
2. 分类
  * 全局作用域
  * 函数作用域
  * 没有块作用域(ES6有了)
3. 作用
  * 隔离变量,不同作用域下同名变量不会有冲突
-->
<script type="text/javascript"> /* 
    //没有块作用域
    if(true){
        var c=3;
    }
    console.log(c); */

    var a=10;
    var b=20;
    function fn(x){
        var a=100;
        var c=300;
        console.log('fn()',a,b,c,x);
        function bar(x){
            var a=1000;
            var d=400;
            console.log('bar()',a,b,c,d,x);
        }
        bar(100);
        bar(200);
    }
    fn(10); </script>
</body>
</html> 

2、作用域与执行上下文

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>02_作用域与执行上下文</title>
</head>
<body>
<!--
1. 区别1
  * 全局作用域之外,每个函数都会创建自己的作用域,作用域在函数定义时就已经确定了。而不是在函数调用时
  * 全局执行上下文环境是在全局作用域确定之后, js代码马上执行之前创建
  * 函数执行上下文环境是在调用函数时, 函数体代码执行之前创建
2. 区别2
  * 作用域是静态的, 只要函数定义好了就一直存在, 且不会再变化
  * 执行上下文环境是动态的, 调用函数时创建, 函数调用结束时上下文环境就会自动释放
3. 联系
  * 执行上下文环境(对象)是从属于所在的作用域
  * 全局上下文环境==>全局作用域
  * 函数上下文环境==>对应的函数使用域
-->
<script type="text/javascript"> var a=10;
    var b=20;
    function fn(x){
        var a=100;
        var c=300;
        console.log('fn()',a,b,c,x);
        function bar(x){
            var a=1000;
            var d=400;
            console.log('bar()',a,b,c,d,x);
        }
        bar(100);
        bar(200);
    }
    fn(10); </script>
</body>
</html> 

3、作用域链

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>03_作用域链</title>
</head>
<body>
<!--
1. 理解
  * 多个上下级关系的作用域形成的链, 它的方向是从下向上的(从内到外)
  * 查找变量时就是沿着作用域链来查找的
2. 查找一个变量的查找规则
  * 在当前作用域下的执行上下文中查找对应的属性, 如果有直接返回, 否则进入2
  * 在上一级作用域的执行上下文中查找对应的属性, 如果有直接返回, 否则进入3
  * 再次执行2的相同操作, 直到全局作用域, 如果还找不到就抛出找不到的异常
-->
<script type="text/javascript"> var a=1;
    function fn1(){
        var b=2;
        function fn2(){
            var c=3;
            console.log(c);//3
            console.log(b);//2
            console.log(a);//1
            console.log(d);//not defined
        }
        fn2();
    }
    fn1(); </script>

</body>
</html> 

4、作用域面试题

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>04_作用域_面试题</title>
</head>
<body>
<script type="text/javascript"> var x=10;
    function fn(){
        console.log(x);
    }
    function show(f){
        var x=20;
        f();
    }
    show(fn);//10 </script>
</body>
</html> 

5、作用域面试题

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>04_作用域_面试题2</title>
</head>
<body>
<script type="text/javascript"> var fn=function(){
        console.log(fn);//现在函数自身里面找,找不到,再到全局作用域找,找到fn
    };
    fn();//fn=function(){console.log(fn);};

    var obj={
        fn2:function(){
            // console.log(fn2);
            console.log(this.fn2);
        }
    };
    obj.fn2(); </script>
</body>
</html> 

4、闭包

1、引入

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>00_引入</title>
</head>
<body>

<button>测试1</button>
<button>测试2</button>
<button>测试3</button>
<!--
需求: 点击某个按钮, 提示"点击的是第n个按钮"
-->
<script type="text/javascript"> var btns=document.getElementsByTagName("button");
        var length = btns.length;
        // 遍历添加点击事件
        /* 
        for(var i=0;i<length;i++){
            var btn=btns[i];
            btn.onclick=function(){
                alert("点击的是第"+(i+1)+"个按钮!");//
            }
        } */
        // console.log(i);//3

        /* for(var i=0;i<length;i++){
            var btn=btns[i];
            // 将btn所对应的下标保存到index属性上
            btn.index=i;
            btn.onclick=function(){
                alert("点击的是第"+(this.index+1)+"个按钮!");//
            }
        } */

        // 利用了闭包
        for(var i=0;i<length;i++){
            (function (i){
                var btn=btns[i];
                btn.onclick=function(){
                    alert("第"+(i+1)+"个");
                }
            })(i)
        } </script>
</body>

</html> 

2、理解闭包

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>01_理解闭包</title>
</head>
<body>
<!--
1. 如何产生闭包?
  * 当一个嵌套的内部(子)函数引用了嵌套的外部(父)函数的变量(函数)时, 就产生了闭包
2. 闭包到底是什么?
  * 使用chrome调试查看
  * 理解一: 闭包是嵌套的内部函数(绝大部分人)
  * 理解二: 包含被引用变量(函数)的对象(极少数人)
  * 注意: 闭包存在于嵌套的内部函数中
3. 产生闭包的条件?
  * 函数嵌套
  * 内部函数引用了外部函数的数据(变量/函数)
-->
<script type="text/javascript"> function fn1(){
        var a=2;
        var b='abc';
        function fn2(){//执行函数定义就好产生闭包(不用调用内部函数)
            console.log(a);
        }
        fn2();
    }
    fn1(); </script>
</body>
</html> 

3、常见的闭包

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>02_常见的闭包</title>

</head>
<body>
<!--
1. 将函数作为另一个函数的返回值
2. 将函数作为实参传递给另一个函数调用
-->
<script type="text/javascript"> //1、将函数作为另一个函数的返回值
    function fn1(){
        var a=2;
        function fn2(){
            a++;
            console.log(a);
        }
        return fn2;
    }
    var f = fn1();
    f();//3
    f();//4

    // fn1();

    //2、将函数作为实参传递给另一个函数调用
    function showDelay(msg,time){
        setTimeout(function(){
            alert(msg);
        },time);
    }
    showDelay('xiaolin',2000); </script>
</body>
</html> 

4、闭包的作用

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>03_闭包的作用</title>

</head>
<body>
<!--
1. 使用函数内部的变量在函数执行完后, 仍然存活在内存中(延长了局部变量的生命周期)
2. 让函数外部可以操作(读写)到函数内部的数据(变量/函数)

问题:
  1. 函数执行完后, 函数内部声明的局部变量是否还存在?  一般是不存在了,存在于闭包中的变量才可能存在
  2. 在函数外部能直接访问函数内部的局部变量吗? 不能,但是我们可以通过闭包让外部操作它
-->
<script type="text/javascript"> //1、将函数作为另一个函数的返回值
    function fn1(){
        var a=2;
        function fn2(){
            a++;
            console.log(a);
        }

        function fn3(){
            a--;
            console.log(a);
        }

        return fn3;
    }
    var f = fn1();
    f();//1
    f();//0 </script>
    
</body>
</html> 

5、闭包的生命周期

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>04_闭包的生命周期</title>

</head>
<body>
<!--
1. 产生: 在嵌套内部函数定义执行完时就产生了(不是在调用)
2. 死亡: 在嵌套的内部函数成为垃圾对象时
-->
<script type="text/javascript"> //1、将函数作为另一个函数的返回值
    function fn1(){
        // 此时闭包就已经产生了(函数提升,内部函数对象已经创建了)
        var a=2;
        function fn2(){
            a++;
            console.log(a);
        }
        return fn2;
    }
    var f = fn1();
    f();//3
    f();//4
    f=null;//让闭包死亡(包含闭包的函数对象成为了垃圾对象) </script>
</body>
</html> 

6、闭包的应用---自定义js模块

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>05_闭包的应用_自定义JS模块</title>
</head>
<body>
<!--
闭包的应用2 : 定义JS模块
  * 具有特定功能的js文件
  * 将所有的数据和功能都封装在一个函数内部(私有的)
  * 只向外暴露一个包信n个方法的对象或函数
  * 模块的使用者, 只需要通过模块暴露的对象调用方法来实现对应的功能
-->
<script type="text/javaScript" src="myModule.js"></script>
<script> var module = myModule();
    module.doSomething();//doSomething() MY JAVASCRIPT
    module.doOtherthing();//doOtherthing() my javascript </script>
</body>
</html> 

myModule.js

function myModule(){
    // 私有数据
    var msg="my JavaScript";
    // 操作数据的函数
    function doSomething(){
        console.log('doSomething() '+msg.toUpperCase());
    }
    function doOtherthing(){
        console.log('doOtherthing() '+msg.toLowerCase());
    }

    // 向外暴露对象(给外部使用的方法)
    return {
        doSomething:doSomething,
        doOtherthing:doOtherthing
    };
} 

7、闭包的应用---自定义js模块

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>05_闭包的应用_自定义JS模块2</title>
</head>
<body>
<!--
闭包的应用2 : 定义JS模块
  * 具有特定功能的js文件
  * 将所有的数据和功能都封装在一个函数内部(私有的)
  * 只向外暴露一个包信n个方法的对象或函数
  * 模块的使用者, 只需要通过模块暴露的对象调用方法来实现对应的功能
-->
<script src="myModule2.js"></script>
<script>
    myModule2.doSomething();
    myModule2.doOtherthing();

</script>
</body>
</html> 

myModule2.js

(function(window){
    // 私有数据
    var msg="my JavaScript";
    // 操作数据的函数
    function doSomething(){
        console.log('doSomething() '+msg.toUpperCase());
    }
    function doOtherthing(){
        console.log('doOtherthing() '+msg.toLowerCase());
    }

    window.myModule2={
        doSomething:doSomething,
        doOtherthing:doOtherthing
    };
})(window);//传入window可以实现代码压缩 

8、闭包的缺点及解决

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>06_闭包的缺点及解决</title>
</head>
<body>
<!--
1. 缺点
  * 函数执行完后, 函数内的局部变量没有释放, 占用内存时间会变长
  * 容易造成内存泄露
2. 解决
  * 能不用闭包就不用
  * 及时释放
-->
<script type="text/javascript"> function fn1(){
        var arr=new Array(100000);
        function fn2(){
            console.log(arr.length);
        }
        return fn2;
    }
    var f = fn1();
    f();//100000
    f=null;//让内部函数成为垃圾对象---->回收闭包 </script>
</body>
</html> 

9、内存溢出和内存泄露

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>02_内存溢出与内存泄露</title>
</head>
<body>

<!--
1. 内存溢出
  * 一种程序运行出现的错误
  * 当程序运行需要的内存超过了剩余的内存时, 就出抛出内存溢出的错误
2. 内存泄露
  * 占用的内存没有及时释放
  * 内存泄露积累多了就容易导致内存溢出
  * 常见的内存泄露:
    * 意外的全局变量
    * 没有及时清理的计时器或回调函数
    * 闭包
-->

<script type="text/javascript"> // 1. 内存溢出
  var obj = {};
  for (var i = 0; i < 10000; i++) {
    obj[i] = new Array(1000000);
    // console.log('-----');
  }

  // 2. 内存泄露
    // 意外的全局变量
  function fn() {
    a = new Array(10000000);
    console.log(a);
  }
  fn();

   // 没有及时清理的计时器或回调函数
  var intervalId = setInterval(function () { //启动循环定时器后不清理
    console.log('----');
  }, 1000);

  // clearInterval(intervalId)

    // 闭包
  function fn1() {
    var a = 4;
    function fn2() {
      console.log(++a);
    }
    return fn2;
  }
  var f = fn1();
  f();

  // f = null; </script>
</body>
</html> 

10、面试题1

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>07_面试题1</title>
</head>
<body>

<script type="text/javascript"> //代码片段一
    var name ="The Window";
    var object = {
        name: "My Object",
        getNameFunc : function(){
            return function(){
                return this.name;
            };
        }
    };
    // 没有使用闭包
    // object.getNameFunc()得到的就是一个函数,函数(),里面的this就是window
    alert(object.getNameFunc()());//The Window

    // 代码片段二
    var name2 ="The Window";
    var object2 = {
        name2: "My Object",
        getNameFunc : function(){
            var that=this;
            return function(){
                return that.name2;
            };
        }
    };
    // 使用了闭包
    // object2.getNameFunc()得到一个函数,执行函数,把object2对象赋值给that,that指向object2
    alert(object2.getNameFunc()());//My Object </script>
</body>
</html> 

11、面试题2

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>07_面试题2</title>
</head>
<body>

<script type="text/javascript"> // 关键点在于有没有产生新的闭包

    function fun(n,o){
        console.log(o);
        return {
            fun:function(m){
                return fun(m,n);
            }
        };
    }
    var a =fun(0);//undefined,返回一个对象,产生了闭包
    a.fun(1);//0 m=1,n=0  ==>  输出0 ,产生一个新的闭包,返回了一个对象,但是没有接收,闭包很快就消失了
    a.fun(2);//0 m=2,n=0 同理
    a.fun(3);//0 m=3,n=0 同理
    var b = fun(0).fun(1).fun(2).fun(3);//undefined 0 1 2,返回的对象被接收了,产生了新的闭包
    var c = fun(0).fun(1);//undefined 0
    c.fun(2);//1
    c.fun(3);//1 </script>
</body>
</html> 

三、对象高级

1、对象创建模式

1、Object构造函数模式

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>01_Object构造函数模式</title>
</head>
<body>
<!--
方式一: Object构造函数模式
  * 套路: 先创建空Object对象, 再动态添加属性/方法
  * 适用场景: 起始时不确定对象内部数据
  * 问题: 语句太多
-->
<script type="text/javascript"> /*
  一个人: name:"Tom", age: 12
   */
  var p =new Object();
  p.name='tom';
  p.age=12;
  p.setName=function(name){
    this.name=name;
  }

//   测试
  p.setName('jack');
  console.log(p); </script>
</body>
</html> 

2、对象字面量

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>02_对象字面量</title>
</head>
<body>
<!--
方式二: 对象字面量模式
  * 套路: 使用{}创建对象, 同时指定属性/方法
  * 适用场景: 起始时对象内部数据是确定的
  * 问题: 如果创建多个对象, 有重复代码
-->
<script type="text/javascript"> var p={
        name:'tom',
        age:12,
        setName:function(name){
            this.name=name;
        }
    };

    // 测试
    p.setName('marry');
    console.log(p.name);

    // 代码重复
    var p2={
        name:'jack',
        age:16,
        setName:function(name){
            this.name=name;
        }
    }; </script>
</body>
</html> 

3、工厂模式

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>03_工厂模式</title>
</head>
<body>
<!--
方式三: 工厂模式
  * 套路: 通过工厂函数动态创建对象并返回
  * 适用场景: 需要创建多个对象
  * 问题: 对象没有一个具体的类型, 都是Object类型
-->
<script type="text/javascript"> // 返回一个对象的函数==>工厂函数
    function createPerson(name,age){
        var obj={
            name:name,
            age:age,
            setName:function(name){
            this.name=name;
            }
        };
        return obj;
    }

    function createStudent(name,sno){
        var obj={
            name:name,
            sno:sno,
            setSno:function(sno){
            this.name=sno;
            }
        };
        return obj;
    }

    // 创建2个人
    var p1= createPerson('tom',12);
    var p2= createPerson('jack',15);
    

    var s = createStudent("zs",21281084);

    console.log(typeof p1===typeof s);//true </script>
</body>
</html> 

4、自定义构造模式

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>04_自定义构造函数模式</title>
</head>

<body>
<!--
方式四: 自定义构造函数模式
  * 套路: 自定义构造函数, 通过new创建对象
  * 适用场景: 需要创建多个类型确定的对象
  * 问题: 每个对象都有相同的数据, 浪费内存
-->
<script type="text/javascript"> function Person(name,age){
        this.name=name;
        this.age=age;
        this.setName=function(name){
            this.name=name;
        }
    }

    function Student(name,sno){
        this.name=name;
        this.sno=sno;
        this.setName=function(name){
            this.name=name;
        }
    }


    var p = new Person('zz',18);
    p.setName('jack');
    console.log(p1.name,p.age);
    console.log(p instanceof Person);//true

    var s = new Student('zs',120310);
    console.log(s);
    console(s instanceof Student);//true

    var p2=new Person('fs',12);
    console.log(p1,p2); </script>
</body>
</html> 

5、构造函数+原型的组合模式

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>05_构造函数+原型的组合模式</title>
</head>
<body>
<!--
方式六: 构造函数+原型的组合模式
  * 套路: 自定义构造函数, 属性在函数中初始化, 方法添加到原型上
  * 适用场景: 需要创建多个类型确定的对象
-->
<script type="text/javascript"> function Person(name,age){
        this.name=name;
        this.age=age;
    }

    Person.prototype.setName=function(name){
            this.name=name;
    };

    var p1= new Person('zs',19);
    var p2= new Person('sd',11);
    console.log(p1,p2); </script>
</body>
</html> 

2、继承模式

1、原型链继承

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>01_原型链继承</title>
</head>
<body>
<!--
方式1: 原型链继承
  1. 套路
    1. 定义父类型构造函数
    2. 给父类型的原型添加方法
    3. 定义子类型的构造函数
    4. 创建父类型的对象赋值给子类型的原型
    5. 将子类型原型的构造属性设置为子类型
    6. 给子类型原型添加方法
    7. 创建子类型的对象: 可以调用父类型的方法
  2. 关键
    1. 子类型的原型为父类型的一个实例对象
-->
<script type="text/javascript"> // 父类型
    function Supper(){
        this.supProp="Super property";
    }
    Supper.prototype.showSupperProp=function(){
        console.log(this.supProp);
    }
    // 子类型
    function Sub(){
        this.subProp ="Sub property";
    }
    // 子类型的原型是父类型的一个实例对象
    Sub.prototype = new Supper();
    // 让子类型的原型的constructor指向子类型
    Sub.prototype.constructor=Sub;
    Sub.prototype.showSubProp=function(){
        console.log(this.subProp);
    }

    var sub=new Sub();
    sub.showSupperProp();
    // sub.toString();
    sub.showSubProp();


    console.log(sub.constructor); </script>
</body>
</html> 

image-20221030210038378

2、借用构造函数继承

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>02_借用构造函数继承</title>
</head>
<body>
<!--
方式2: 借用构造函数继承(假的)
1. 套路:
  1. 定义父类型构造函数
  2. 定义子类型构造函数
  3. 在子类型构造函数中调用父类型构造
2. 关键:
  1. 在子类型构造函数中通用call()调用父类型构造函数
-->
<script type="text/javascript"> function Person(name,age){
        this.name = name;
        this.age=age;
    }
    function Student(name,age,price){
        Person.call(this,name,age);//相当于this.Person(name,age);
        /* this.name = name;
        this.age=age; */
        this.price=price;
    }
    var s=new Student("XiaoLin",21,14000);
    console.log(s.name,s.age,s.price); </script>
</body>
</html> 

3、组合继承

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>03_组合继承</title>
</head>
<body>
<!--
方式3: 原型链+借用构造函数的组合继承
1. 利用原型链实现对父类型对象的方法继承
2. 利用call()借用父类型构建函数初始化相同属性
-->
<script type="text/javascript"> function Person(name,age){
        this.name = name;
        this.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=function(price){
        this.price=price;
    }


    var s=new Student("XiaoLin",21,14000);
    s.setName('xiaolin');
    s.setPrice(15000);
    console.log(s.name,s.age,s.price); </script>
</body>
</html> 

四、线程机制与事件机制

1、进程与线程

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>01_进程与线程</title>
</head>
<body>
<!--
1. 进程:程序的一次执行, 它占有一片独有的内存空间。分配资源的最小单位
2. 线程: CPU的基本调度单位, 是程序执行的一个完整流程,cpu调度的最小单位
3. 进程与线程
  * 应用程序必须运行在某个进程的某个线程上
  * 一个进程中一般至少有一个运行的线程: 主线程,进程启动后自动创建的
  * 一个进程中也可以同时运行多个线程, 我们会说程序是多线程运行的
  * 一个进程内的数据可以供其中的多个线程直接共享
  * 多个进程之间的数据是不能直接共享的
  * 线程池(thread pool):保存多个线程对象的容器,实现线程对象的反复利用
4. 浏览器运行是单进程还是多进程?
  * 有的是单进程
    * firefox
    * 老版IE
  * 有的是多进程
    * chrome
    * 新版IE
5. 如何查看浏览器是否是多进程运行的呢?
  * 任务管理器==>进程
6. 浏览器运行是单线程还是多线程?
  * 都是多线程运行的
7、 什么是多进程和多线程?
    多进程:一个应用程序可以同时启动多个实例运行
    多线程:在一个进程内,同时有多个线程运行
8、比较单线程和多线程
    多线程:
        优点:有效提升cpu的利用率
        缺点:创建多线程开销、线程间切换开销(单核)、死锁与状态同步问题
    单线程:
        优点:顺序编程简单易懂
        缺点:效率低
9、 js是单线程还是多线程?
    js是单线程运行的
    但是使用Html5的Web Workes可以多线程运行
-->
</body>
</html> 

image-20221030213026655

2、浏览器内核

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>02_浏览器内核</title>
</head>
<body>
<!--
1. 什么是浏览器内核?
  * 支持浏览器运行的最核心的程序
2. 不同的浏览器可能不太一样
  * Chrome, Safari: webkit
  * firefox: Gecko
  * IE: Trident
  * 360,搜狗等国内浏览器: Trident + webkit
3. 内核由很多模块组成
  主  * js引擎模块:负责js程序的编译与运行
  线 * html,css文档解析模块 : 负责页面文本的解析
  程 *dom/css模块 : 负责dom/css在内存中的相关处理
     * 布局和渲染模块 : 负责页面的布局和效果的绘制


  分 * 定时器模块 : 负责定时器的管理
  线 * 网络请求模块 : 负责服务器请求(常规/Ajax)
  程 * 事件响应模块 : 负责事件的管理
-->
</body>
</html> 

3、定时器引发的思考

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>03_定时器引发的思考</title>
</head>
<body>

<button id="btn">启动定时器</button>

<!--
1. 定时器真是定时执行的吗?
  * 定时器并不能保证真正定时执行
  * 一般会延迟一丁点(可以接受), 也有可能延迟很长时间(不能接受)
2. 定时器回调函数是在分线程执行的吗?
  * 在主线程执行的, js是单线程的
3. 定时器是如何实现的?
  * 事件循环模型(后面讲)
-->
<script type="text/javascript"> var btn = document.getElementById('btn');
    btn.onclick=function(){
        // var start = new Date.getTime();
        var start = Date.now();
        console.log('启动定时器前...');
        setTimeout(function(){
            console.log('定时器执行了',Date.now()-start);
        },200);
        console.log('启动定时器后...');

        // 做一个长时间的工作
        for(var i=0;i<1000000000;i++){

        }
        // 定时器执行时间延迟了
    }; </script>
</body>
</html> 

4、js是单线程执行的

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>04_JS是单线程的</title>
</head>
<body>
<!--
1. 如何证明js执行是单线程的?
  * setTimeout()的回调函数是在主线程执行的
  * 定时器回调函数只有在运行栈中的代码全部执行完后才有可能执行
2. 为什么js要用单线程模式, 而不用多线程模式?
  * JavaScript的单线程,与它的用途有关。
  * 作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。
  * 这决定了它只能是单线程,否则会带来很复杂的同步问题

3. 代码的分类:
  * 初始化代码
  * 回调代码
4. js引擎执行代码的基本流程
  * 先执行初始化代码: 包含一些特别的代码    回调函数(异步执行)
    * 设置定时器
    * 绑定事件监听
    * 发送ajax请求
  * 后面在某个时刻才会执行回调代码
-->
<script type="text/javascript"> setTimeout(function(){
        console.log('timeout 2222');
        alert('22222');
    },5000);
    setTimeout(function(){
        console.log('timeout 1111');
        alert('11111');
    },3000);
    setTimeout(function(){
        console.log('timeout 0000');
    },0);//alert----先输出

    function fn(){
        console.log('fn()');
    }
    fn();
    // 先输出1,再1111,再2222

    console.log('alert()之前');
    alert('------');//暂停当前主线程的执行,也暂停了计时,点击确定后才恢复程序的执行和计时,现在2022并不会暂停计时
    console.log('alert()之后'); </script>
</body>
</html> 

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

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>05_事件循环模型</title>
</head>
<body>
<button id="btn">测试</button>
<!--
1. 所有代码分类
  * 初始化执行代码(同步代码): 包含绑定dom事件监听, 设置定时器, 发送ajax请求的代码
  * 回调执行代码(异步代码): 处理回调逻辑
2. js引擎执行代码的基本流程:
  * 初始化代码===>回调代码
3. 模型的2个重要组成部分:
  * 事件(定时器/DOM事件/Ajax)管理模块
  * 回调队列
4. 模型的运转流程
  * 执行初始化代码, 将事件回调函数交给对应模块管理
  * 当事件发生时, 管理模块会将回调函数及其数据添加到回调列队中
  * 只有当初始化代码执行完后(可能要一定时间), 才会遍历读取回调队列中的回调函数执行
-->
<script type="text/javascript"> function fn1(){
        console.log('fn1()');
    }
    fn1();
    var btn=document.getElementById('btn');
    btn.onclick=function(){
        console.log('点击了btn');
    };
    setTimeout(function(){
        console.log('定时器执行了');
    },2000);
    function fn2(){
        console.log('fn2()');
    }
    fn2();
    // fn1(),fn2(); </script>
</body>
</html> 

image-20221030224330853

image-20221030225429596

6、H5 Web Workers(多线程)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>06_Web Workers_测试</title>
</head>
<body>
<!--
1. H5规范提供了js分线程的实现, 取名为: Web Workers
2. 相关API
  * Worker: 构造函数, 加载分线程执行的js文件
  * Worker.prototype.onmessage: 用于接收另一个线程的回调函数
  * Worker.prototype.postMessage: 向另一个线程发送消息
3. 不足
  * worker内代码不能操作DOM(更新UI)
  * 不能跨域加载JS
  * 不是每个浏览器都支持这个新特性
-->
<input type="text" placeholder="数值">
<button id="btn">计算</button>
<script type="text/javascript"> // 编程实现斐波那契数列(Fibonacc sequence)的计算
    // F(0)=0,F(1)=1,....F(n)=F(n-1)+F(n-2);
    function fibonacci(n){
        return number<=2 ? 1: fibonacci(number-1)+fibonacci(number-2);
        /* var res = [0, 1];
        if(n < 2) {
            return res[n];
        }
        var first = 0;
        var second = 1;
        var fibn = 0;
        for(var i = 2; i <= n; i++) {
            fibn = first + second;
            first = second;
            second = fibn;
        }
        return fibn; */
    }
    // 获取输入框中的内容
    var input = document.getElementsByTagName("input")[0];
    document.getElementById('btn').onclick=function(){
        var num = input.value;
        var result = fibonacci(num);
        alert(result);
    } </script>
</body>
</html> 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <input type="text" placeholder="数值" id="number">
    <button id="btn">计算</button>
    <script> var input = document.getElementById("number");
        document.getElementById('btn').onclick=function(){
        var number = input.value;
        // 创建一个worker对象
        var worker = new Worker('worker.js');
        // 绑定接收消息监听
        worker.onmessage=function(event){
            console.log('主线程接收分线程返回的数据:'+event.data);
            alert(event.data);
        }
        // 向分线程发送数据
        worker.postMessage(number);
        console.log('主线程向分线程发送的数据:'+number);
    } </script>
</body>
</html> 
function fibonacci(number){
    return number<=2 ? 1: fibonacci(number-1)+fibonacci(number-2);
    /* var res = [0, 1];
    if(n < 2) {
        return res[n];
    }
    var first = 0;
    var second = 1;
    var fibn = 0;
    for(var i = 2; i <= n; i++) {
        fibn = first + second;
        first = second;
        second = fibn;
    }
    return fibn; */
}

var onmessage = function(event){
    var num = event.data;
    console.log("分线程接收到主线程发送来的数据:"+num);
    // 计算
    var result = fibonacci(num);
    postMessage(result);
    console.log('分线程向主线程返回数据:'+result);
    // alert(result);//alert是window的方法。在分线程不能调用
    // 分线程中的全局对象不再是window,所以分线程不可能更新线程
    
}

console.log(this); 

image-20221030225622244

image-20221030234219893

本文作者:_xiaolin

本文链接:https://www.cnblogs.com/SilverStar/p/17415637.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   _xiaolin  阅读(0)  评论(0编辑  收藏  举报  
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起