JavaScript高级

640

第一部分:基础总结深入

1.1 数据类型

  • 基本类型(值类型)

      String:任意的字符串
      Number:任意的数字
      Booleantruefalse
      Nullnull
      Undefinedundefined
    
  • 对象(引用类型)

     Object:  任意对象都是Object类型
     Function:一种特别的对象(特别在哪?可以调用执行)
     Array
  • 判断

    typeOf undefined、数值、字符串、布尔值

    instanceOf 专门用来判断对象的具体类型:函数?数组?

    == === 可以判断undefined、null的数据类型

1.2 数据类型相关问题

1、null和undefined区别

   var a
   console.log(a)   //undefined

   a=null
   console.log(a)  //null
      

2、什么时候给变量设值为null

var b=null  //初始赋值为null,表名将要赋值为对象
b=[1,2,3,4]
b=null    //释放数组所占用的内存,让b指向的对象成为垃圾对象(被垃圾回收器回收)
console.log("b",b)

3、严格区分变量类型和数据类型

  • 数据的类型

     基本类型
     对象类型
    
  • 变量的类型

    变量本身没有类型
    
     基本类型:保存的是基本类型的数据
     引用类型 :保存的是地址值
    
     
     var c={}
     console.log(typeof c)  //object
      
     var d=function(){}
     console.log(typeof d)   //function
    

1.3 数据、变量、内存三者之间的关系

什么是数据?
    存储在内存中代表特定信息的,本质上是0101....
    
    数据特点:可传递、可运算
    
    一切皆数据
    
    内存中所有操作的目标:数据
    
    
    
什么是内存
     内存条通电后产生的可存储数据的空间

     内存产生和死亡:内存条===》通电===》产生内存空间===》存储数据===》处理数据===》断电 ===》内存空间和数据都消失
     
     一块内存有两个数据
     
        1、内部存储的数据
        2、地址值数据 
        
     内存的分类
         
         栈:全局变量和局部变量
         堆:对象
     
什么是变量
    可变化的量,变量名和变量值组成
    每个变量都定义一块小内存
    变量名用来查找对应的内存
    变量值就是内存中保存的数据
    
    var age=18
数据、变量、内存关系?
    内存是用来存储数据的空间
    变量是内存的标识,变量名查找内存空间
    
关于赋值和内存的问题
    var a=XXX,a内存中到底保存的是什么
    XXX是基本数据,保存的就是这个数据
    XXX是对象,保存的是对象的地址
    XXX是变量 保存的可能是基本类型数据,也可能是地址
         var b='abc'
         var b=function(){}
         var a=b
关于引用变量的赋值问题
    var obj1={name:'TOM'}
    var obj2=obj1    //将obj1内存的内容保存在obj2中,只不过obj1内存的内容是地址值
    
    obj1.name='Jack'
    console.log(obj2.name)   //jack
    
  两个引用变量指向同一个对象,其中一个变量修改了对象内部的数据,另一个对象看到的是修改之后的数据
  
  var A={name:'vina'}
    function fn(obj){
         obj.name='bbb'
    }
    fn(A)
    console.log(A)   //{ name: 'bbb' }
    var A={name:'vina'}
    function fn(obj){
         obj={name:'ppp'}
    }
    fn(A)
    console.log(A)    //{ name: 'vina' }
在js调用函数传递变量参数是,是值传递还是引用传递
  理解1: 都是值传递,只是这个值有两种情况,一个基本类型值,一个地址值
  理解2:可能是值传递,也可能是引用传递,只是看你怎么理解吧地址值传递给形参算是值传递还是引用传递,
     
      var a=3
      function fn(a){
          a=a+1
      }
      fn(a)
      console.log(a)   //3

      var obj={a:3}
      function fn(obj){
          obj.b=4
      }
      fn(obj)
      console.log(obj)  //{ a: 3, b: 4 }
JS引擎如何管理内存
  • 内存生命周期

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

    全局变量:是不会被释放的

    var obj={}   
    obj=null 
    

    局部变量:函数执行完自动释放

    //执行完fn,b的内存空间自动释放,b所指向的对象是在后面的某个时刻,由垃圾回收器释放回收
     function fn(){
         var b=4
     }
    
    

1.4 对象

1、什么是对象?
   多个数据的封装体
   用来保存多个数据的容器
   一个对象代表现实世界中的一个事务
  var obj= {
      name:'Tom',
      age:13,
      setName:function(name){
          this.name=name
      }
      setAge:function(age){
          this.age=age
      }
   }
2、为什么要用对象?
   对象是用来管理多个数据
   obj.name='vina'
   
   
3、对象的组成?
   属性:属性名(字符串)和属性值(任意类型)组成
        (在语言的设计的时候允许属性名不写单引号、双引号,但是并不能改变属性名是字符串的事实)
   方法:一种特别的属性(属性值是方法)
   
4、如何访问对象内部的数据?
 对象.属性名(编码简单,有时不能用)
 对象[age](编码麻烦,通用)
     1、当属性名有横杠连接的时候,必须用 对象[age]
     p['content-type']='text/json'
     console.log( p['content-type'])
     2、变量名不确定(变量名是一个变量)
     var propName='myAge'
     var value=18
     p.propName=value(错误写法❌)
     p[propName]=value(✅)
 p.setName('richur')
console.log(obj.name,obj[age])

第二部分:函数高级

2.1 函数

1、什么是函数?
 实现特定功能的n条语句的封装体
 只有函数是可以执行的,其他类型的数据是不能执行的
2、为什么要用函数
 提高代码复用
 便于阅读交流
 体现的就是封装的思想
 
 
3、如何定义函数

函数声明

     function fn(){
        console.log("aaa")
     }

表达式

  var fn2=function(){
     console.log("fn2")
 }
4、如何调用函数
 test()   //直接调用
 obj.test()    //通过对象调用
 new test()   new调用
 test.call/apply(obj)    //相当于obj.text()  这种调用方式只是临时让test成为obj的方法进行调用
 
     var obj={}
        function test2(){
            this.age=12
        }
        test2.call(obj)
        console.log(obj)  //{ age: 12 }
        // 可以让一个函数成为指定任意对象的方法进行调用
     

2.2 回调函数

1.什么函数才是回调函数
特点:
   你定义了
   你没有调用
   但是他执行了
2.常见的回调函数
  DOM事件回调
  定时器回调函数
  ajax请求回调函数
  生命周期回调函数

2.3 IFEE

全称 immediately-Invoked Function Expression 立即回调函数表达式 作用:隐藏实现、不会污染外面的命名空间,用它编写js模块

   (function(){  //匿名函数自调用
       console.log("aaaa")
   })() 
      

为什么还要用函数呢?不直接输出console.log("aaaa")

 隐藏实现
 不会污染外面的命名空间 
 
    ;(function(){
       var a=1
       function test(){
          console.log(++a)
       }
    window.$=function(){ //向外暴露一个全局函数
       return {
            test:test
       }
    }
  })()

  $().test()    //$是一个函数,$执行后返回的是一个对象

2.4 this

1.this是什么?
  • 任何函数本质上都是通过某个对象来调用的,如果没有直接指定就是window
  • 所有函数内部都有一个变量this,他的值是调用函数的当前对象
2.如何确定this
  • this() :window

  • p.test() :新创建的对象

  • p.call(obj) :obj

3.1 原型与原型链

1、原型

  • 任何函数都有一个prototype属性,它默认指向Object空对象(被称为:原型对象)

    typeof Date.prototype  //"object",有一堆属性,
    
    
    function fun(){
    }
    console.log(fun.prototype)  //默认指向一个Object空对象(没有我们的属性)
    fun.prototype.test=function(){}
     console.log(fun.prototype)
     
     
    
  • 原型对象中有一个属性constructor,他指向函数对象

    console.log(Date.prototype.constructor===Date)  //true
    console.log(Date.prototype.constructor===fun)  //true
    
    

image.png

  • 给原型对象添加属性(一般是方法===》实例对象可以访问)

    fun.prototype.test=function(){
        console.log("test")
    }
    //创建实例f1
    var f1=new fun()
    f1.test()
    

2、显式原型和隐式原型

  • 每个函数都有一个prototype,是在定义函数时默认添加的,即显式属性,默认指向一个空的Object对象

         function Fn(){  //内部语句:this.prototype={}
         }
         console.log(Fn.prototype)
         
    
  • 每个实例对象都有一个__proto__,是在创建对象时添加的,可以称为隐式原型,默认指向一个空的Object对象

       var fn=new Fn()  //内部this.__proto==Fun.prototype
       console.log(fn.__proto__)
       
    
  • 对象的隐式原型的值为其对应构造函数显式原型的值

      console.log(Fn.prototype===fn.__proto__)  //true
    
  • 通过实例对象调用test方法

     //程序员可以直接操作显示原型,但是不能直接操作隐式原型(ES6之前)
     Fn.prototype.test()=function(){
             console.log('test')
         }
     fn.test()
    

image.png

3、原型链(隐式原型链)

当我们去访问一个对象的属性的时候,首先根据这个属性找到属性值,属性值可以为函数。

作用:查找对象属性(方法) 查找过程:现在自身属性中查找,找到就返回,如果没有,再沿着__proto__这条原型链查找,找到返回,如果最终没有找到,返回undefined

  • 原型链

image.png

Object.prototype.proto //null,所以Object的原型对象就是尽头

  • 创建对象

两种创建实例对象方法,实例对象都有隐式原型属性,隐式原型属性指向的是Object原型

var o1=new Object()
var o2={}

image.png

  • 定义function
function Foo(){ }
var Foo=new Function()
Function=new Function()  //只有这个显示原型等于它的隐式原型

//所有函数的__proto__都是相等的,因为都是new Function产生的

首先创建函数对象Foo,函数对象有一个显示原型属性,默认是一个空的Object对象. 函数对象也是Function的实例对象,Function是函数类型

image.png

  • 原型继承

      构造函数的实例对象自动拥有构造函数原型对象的属性(方法)
      利用的就是原型链
    

复习:

1、 函数的显式原型指向的对象:默认是空的Object实例对象(但是不适用于Object这个函数)

   Fn.prototype instanceof Object  //true
   Object.prototype instanceof Object  //false,只有Object是个例外                  Function.prototype instanceof Object  //true

2、

  • Function是new Function()创建的,所以Function是自身的属性

  • 所有函数都是Function的实例(包括Function本身),没有例外

    Function.__proto__ ===Function.prototype
    
  • Object的原型对象是原型链的尽头

    Object.prototype.__proto__  ===null
    

3、

  • 读取对象的属性值的时候:会自动查找原型链中查找

  • 设置对象的属性值,不会查找原型链,如果当前对象中没有此属性,直接添加此属性并且设置值

  • 方法一般定义在原型中,属性一般通过构造函数定义在对象本身上 (因为每个对象方法一样,属性值不一样)

4、探索instanceOf

instanceOf是如何判断的?

  • 表达式: A instanceOf B

  • 如果B函数的显示原型对象在A对象的原型链上,返回true,否则返回false

    B是函数,有显式原型 A是实例,有隐式原型,实例对象可以沿着__proto__这条原型链

image.png

 function Foo(){}
 var f1=new Foo()

 console.log(f1 instanceof Foo)   //true
 console.log(f1 instanceof Object)   //true


image.png

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

image.png 上图可以看出Object有双重身份,可以一步到原型链尽头,也可以两步,通过Function到尽头

    console.log(Object instanceof Function)  //true
    console.log(Object instanceof Object)  //true
    
    

5、面试题

image.png A.prototype={n:2,m:3} //重新给function.prototype赋值

image.png

3.2 执行上下文和执行上下文栈

1、变量提升和函数提升

变量提升

 通过var定义(声明)的变量在定义语句之前就可以访问到,只是值为undefined
   
   var a=3
   console.log(3)  //undefined
 

函数提升

  通过function声明的函数,在之前就可以直接调用
  值:函数定义
    
    f1()  //不可调用,变量提升
    f2()  //可调用,函数提升
    var  f1=function(){
        console.log("f1")
    }
    function f2(){
        console.log("f2")
    }  

2、执行上下文

  • 在执行全局代码前把window确定为全部执行上下文

  • 对全局数据进行预处理

  • var 定义的全局变量=undefined,添加到window属性

  • function声明的全局函数==》赋值,添加未window的方法

  • this=window

函数执行上下文

*在调用函数,准备执行函数体之前,创建对应的函数执行上下文对象
*对局部数据进行预处理
   1、形参变量赋值为实参数据,添加未执行上下文的属性
   2arguments代表所有的实参列表,函数体执行之前arguments已经在了
   3var定义的局部变量提升赋值为undefined,添加未执行上下文的属性
   4function声明的全局函数==》赋值,添加未执行上下文的属性
   5this指定为调用函数的对象,直接调用就是window
   

3、执行上下文栈

*在全局代码执行前,JS引擎就会创建一个栈来存储管理所有的执行上下文对象
*在全家有执行上下文(window)确定后,将其添加到栈中
* 在函数执行上下文创建后,将其添加到栈中(压栈)
* 当前函数执行完,将栈顶的对象移除
当所有的代码执行完,栈中只剩下window

4、面试题

console.log('gb:'+i)
var i=0
foo(1)
function foo(i){
    if(i==4){
        return
    }
    console.log('fb:'+i)
    foo(i+1)
    console.log('fe:'+i)
}

gb:undefined
fb:1
fb:2
fb:3
fe:3
fe:2
fe:1

变量提升和函数提升先执行哪一个?

  先执行变量提升,再执行函数提升
      function a(){
       }
      var a;
      typeof a   //function

  
    if(!(b in window)){
        var b=1
    }
    console.log(b)  //undefined


    var c=1
    function c(c){
        console.log(c)
    }
    c(2) //报错,c不是一个函数,原因是变量和函数都提升了,赋值=1在后面,所以c不是function
    
    

image.png

3.3 作用域和作用域链

作用域

作用:隔离作用域,在不同作用域中,同名变量不会冲突

console.log('------',c)  //不报错,undefined,说明下面不存在块作用域
if(true){
    var c=3
}
console.log('------',c)

作用域、和执行上下文区别

区别

   1、全局作用域未每个函数都创建自己的作用域,作用域在定义的时候已经确定的,而不是在函数调用时
      全局执行上下文环境是在全局作用域确定之后,js代码马上执行之前创建的
      函数执行上下文是在调用函数时,函数体执行之前创建
      
      
   2、作用域是静态的,只有函数定义好了就一直存在,而且不会再变化
      上下文环境是动态的,调用函数时创建的,函数调用结束后上下文环境就会被释放

联系

   执行上下文是从属于所在的作用域
作用域链

理解:

多个上下级的关系的作用域形成链,它的方向是从下向上的(从内到外)
查找变量时沿着作用域链来查找

查找变量的规则

在当前作用域的执行上下文中查找对应的属性,如果找到直接返回,否则进入2
在上一级作用域的执行上下文忠查找对应的属性,如果有直接返回,否则进入3
再执行2的相同操作,知道全局作用域,如果还找不到就抛出找不到的异常

3.4 闭包

    <!-- 点击按钮 -->
    <button>测试1</button>
    <button>测试2</button>
    <button>测试3</button>
    <script>
        var btns=document.getElementsByTagName('button')  //btns是一个伪数组
        //遍历加监听
        // for(var  i=0,length=btns.length;i<length;i++){
        //       var btn=btns[i]
        //       btn.onclick=function(){
        //           console.log("我被点击啦",i)
        //       }
        // }
       
        // 第一种解决方法:闭包
          for(var  i=0,length=btns.length;i<length;i++){
             (function(i){
                 var btn=btns[i]
                 btn.onclick=function(){
                    console.log("我被点击啦",i)
                 }

             })(i)
        }

    </script>

1.如何产生闭包?
   1. 当已和嵌套的内部(子)函数引用了嵌套的外部(父)函数的变量(函数)时,就产生了闭包
   2. 调用外部函数
2. 闭包到底是什么?
   理解1:闭包是嵌套的内部函数(大多数人)
   理解2:包含被引用变量(函数)的对象(极少数人)
   注意:闭包存在于嵌套的内部函数中
   
   
         
3.产生闭包的条件
将函数作为另一个函数的返回值
将函数作为实参传递给另一个函数调用
  
````
function fn1(){
    var a=2
    function fn2(){
        a++
        console.log(a)
    }
    return fn2
}
var f=fn1()
f()  //3
f()   //4

fn1()
//整个过程中产生了几个闭包?  判断几个闭包,主要看外部函数执行了几次

```
4.闭包作用
1.使用函数内部的变量在函数执行完后,仍然存活在内存中(延长局部变量的生命周期)
2.在函数外部能直接访问团函数内部的局部变量吗?通过闭包,我们可以函数外部操作函数内部数据
3.函数执行完后,函数内部的变量是否还存在?一般不存在,存在于闭包中的变量才有可能存在


   ```
   
     function fn1(){
     //此时闭包已经产生了,因为内部函数提升已经创建了
        var a=2
        function fn2(){
           a++
        console.log(a)
        }
       return fn2
    }
    var f=fn1()
    f()  //3  //f指向了fn2的返回值
    f()   //4
   
   ```
5.闭包的生命周期
产生:在嵌套内部函数定义执行完就产生了(不是在调用)
死亡:再嵌套的内部函数成为垃圾对象时


     function fn1(){
     //此时闭包已经产生了,因为内部函数提升已经创建了
        var a=2
        function fn2(){
           a++
        console.log(a)
        }
       return fn2
    }
    var f=fn1()
    f()  //3  //f指向了fn2的返回值
    f()   //4
    f=null  //闭包死亡(包含闭包的函数对象成为了垃圾对象)

    
    
    
      function fn1(){
     //此时闭包已经产生了,因为内部函数提升已经创建了
        var a=2
       fn2= function(){  
           a++
        console.log(a)
        } //在这里闭包产生了
       return fn2
    }
    var f=fn1()
    f()  //3  //f指向了fn2的返回值
    f()   //4
    f=null  //闭包死亡(包含闭包的函数对象成为了垃圾对象
6.闭包的应用
 具有特定功能的js文件
 将所有的数据和功能都封装在一个函数内部(私有)
 只向外暴露已和包含n个方法的对象
 模块的使用者通过模块暴露的对象调用方法来实现相应的功能
 

方法1:

function myModule(){
    var msg="Hello world"
    function something(){
        console.log("something"+msg.toLowerCase())
    }
    function otherthing(){
        console.log("otherthing"+msg.toUpperCase())
    }


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



//外部访问(必须先执行函数)
var fn=myModule()
fn.something()
fn.otherthing()

方法2

(function (){
    var msg="Hello world"
    function something(){
        console.log("something"+msg.toLowerCase())
    }
    function otherthing(){
        console.log("otherthing"+msg.toUpperCase())
    }


    //向外暴露对象(给外部使用的方法)
    window.module2= {
        something:something,
        otherthing:otherthing,
    }
})()




//外部使用(使用起来更方便)

module2.something()
module2.otherthing()

7.闭包的缺点
函数执行完后,函数内的局部变量没有释放,占用内存的时间长
容易造成内存泄漏

解决

能不用闭包就不用
及时释放
8.内存溢出和内存泄漏

内存溢出

   一种程序运行出现的错误
   当程序运行需要的内存超出了剩余的内存时,就抛出内存溢出的错误

var obj={}
for(var i=0;i<10000;i++){
   obj[i]=new Array(100000)
}

内存泄漏

占用的内存没有及时释放
意外的全局变量
没有及时清理的计时器或者回调函数
闭包


//意外的全局变量
function fn(){
   a=3
   console.log(a)
}
9.面试题
var name='The Window'
var object={
    name:'My Object',
    getNameFunc:function(){
        return function(){ 
            return this.name
        }
    }
}
console.log(object.getNameFunc()())  //The window   



var name2='The Window'
var object2={
    name2:'My Object',
    getNameFunc:function(){
    var that=this;
        return function(){ 
            return that.name2
        }
    }
}
console.log(object2.getNameFunc()())  //My Object

第三部分: 面向对象高级

3.1 对象创建模式

第一种写法:

  • 套路:先创建空Object对象,再动态添加属性/方法

  • 适用场景:起始是不确定对象的内部数据

  • 问题:语句太多

       var p=new Object()
        p.name='vina'
        p.age=13
    
        p.setName=function(name){
            this.name=name
        }
        p.setName('Jack')
        console.log(p.name,p.age)  //Jack 13
    
    

第二种写法

  • 套路:使用{}创建对象,同时指定属性和方法

  • 适用场景:起始是确定对象的内部数据

  • 问题:如果创建多个对象,代码很重复

    var p={
        name:'Vina',
        age:13,
        setName:function(name){
            this.name=name
    }
    }
    p.setName('Jack')
    console.log(p.name,p.age)  //Jack 13
    

第三种写法:

  • 套路:使用工厂函数创建对象并返回
  • 适用场景:需要创建多个对象
  • 问题:对象没有一个具体的类型,都是Object类型
    var obj={
        name:name,
        age:age,
        setName:function(name){
            this.name=name
    }
}
  return obj

}

var p1=createPerson('Tom',13)
var p1=createPerson('Vina',18)

第四种写法:

  • 套路:自定义构造函数,通过new创建对象
  • 适用场景:需要创建多个类型片确定的对象
  • 问题:每个对象都是相同的数据,浪费内存

//定义人类型
function Person(name,age){
    this.name=name
    this.age=age
    this.setName=function(name){
        this.name=name
    }
}
var p1=new Person('Tom',12)
p1.setName('Jack')
console.log(p1.name,p1.age)


//定义学生类型
function Student(name,age){
    this.name=name
    this.price=price
    this.setName=function(name){
        this.name=name
    }
}


image.png

第五种写法:

  • 套路:自定义构造函数,属性在函数中初始化,方法添加到原型中
  • 适用场景:需要创建对个类型的确定对象
  • 问题:
    this.name=name
    this.age=age
}
Person.prototype.setName=function(name){
    this.name=name
}

var p1=new Person('Tom',23)
var p2=new Person('Jack',24)

分析:因为方法是写在原型里的,每个对象里只有一般属性,方法在原型里,指向同一个对象,节省内存

image.png

3.2 继承模式

方式1

套路

  * 定义父类型构造函数
  * 给父类型的原型添加方法
  * 定义子类型的构造函数
  * 创建父类型的对象赋值给子类型的原型
  * 将子类型原型的构造属性设置为子类型
  * 给子类型原型添加方法
  * 创建子类型的对象:可以调用父类型的方法

关键

  子类型的原型未父类型的一个实例对象
  

//父类型
function Supper(){
    this.supProp='Supper property'
}
Supper.prototype.showSupperProp=function(){
    console.log(this.supProp)
}
//子类型
function Sub(){
    this.subProp='Sub property'
}
// var sub=new Sub()
// sub.showSupperProp( )   //sub.showSupperProp is not a function,    如果能调用就表示继承了父亲的方法
// sub.toString()  //这个可以,是因为原型对象是一个object实例对象,toString在object原型上

//showSupperProp在Supper的原型上,如果想让sub能看到showSupperProp,必须让sub成为Supper的实例,Supper的实例就能看到原型上的方法,目的达成

Sub.prototype=new Supper()
Sub.prototype.constructor=Sub  //让子类型的原型的Constructor指向子类型
Sub.prototype.showSubProp=function(){
    console.log(this.subProp)
}
var sub=new Sub()
sub.showSupperProp()  //Supper property

image.png

方式2

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

套路:

定义父类型构造函数 定义子类型构造函数 在子类型构造函数中调用父类型构造

关键:

在子类型构造函数中通用super() 调用父类型构造函数


function Person(name,age){
  this.name=name
  this.age=age
}

function Student(name,age,price){
  Person.call(this,name,age)  //相当于this.Person(name,age),相当于Student借用了Person的构造函数,但是没有继承的
  //this.name=name
  //this.age=age
  this.price=price
}

var s=new Student('Tom',20,14000)
console.log(s.name,s.age,s.price)

方式3:组合继承

原型链+借用构造函数的组合继承

  • 1、利用原型链实现父类型片对象的方法继承
  • 2、利用super()借用父类型构建函数初始化相同属性

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.name=name
    // this.age=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('Tom',24,15000)
s.setName('Bob')
s.setPrice(1600)
console.log(s.name,s.age,s.price)  //Bob 24 1600

第三部分:线程机制与事件机制

3.1 进程与线程

进程:程序一次执行,他占有了一片独有的内存空间 可以通过windows任务管理器查看

线程:是进程内的一个独立执行单元 是程序执行的一个完整流程 是CPU的最小的调度单元

image.png

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

何为多进程?

 一个应用程序可以同时启用多个实例运行

何为多线程?

 一个进程内,同时有多个线程运行
 

比较单线程和多线程运行

* 单线程
   
   优点:
    
    顺序编程简单易懂
   
   缺点:
     
     效率低


* 多线程
 
 优点:
 
    能有效提高CPU的利用率
 
 缺点:
 
    创建多线程开销
    线程间切换开销
    死锁与状态同步
    

JS是单线程还是多线程?

   js是单线程运行的
   但是使用H5的web workers可以多线程运行
   
   

浏览器运行是单线程还是多线程?

都是多线程运行的

浏览器运行是多进程还是单进程?

有的是单进程  firefix、老版本IE
有的是多进程  chrome、新版IE
如何查看浏览器是单进程还是多进程?

3.2 浏览器内核

什么叫内核

 支撑浏览器运行最核心的程序
 不同浏览器内核不同
 内核由多个模块组成
 

3.3 定时器引发的思考?

 定时器真的是定时执行的嘛?
 
       定时器并不能保证真正的定时执行
       一般会延迟一丁点,也可能延迟很长时间