JavaScript高级

·  阅读 565

第一部分:基础总结深入

1.1 数据类型

  • 基本类型(值类型)

      String:任意的字符串
      Number:任意的数字
      Boolean:true、false
      Null:null
      Undefined:undefined
    复制代码
  • 对象(引用类型)

     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、形参变量赋值为实参数据,添加未执行上下文的属性
   2、arguments代表所有的实参列表,函数体执行之前arguments已经在了
   3、var定义的局部变量提升赋值为undefined,添加未执行上下文的属性
   4、function声明的全局函数==》赋值,添加未执行上下文的属性
   5、this指定为调用函数的对象,直接调用就是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 定时器引发的思考?

 定时器真的是定时执行的嘛?
 
       定时器并不能保证真正的定时执行
       一般会延迟一丁点,也可能延迟很长时间
    
复制代码
分类:
前端
分类:
前端
收藏成功!
已添加到「」, 点击更改