首页 > 其他分享 >JS高级

JS高级

时间:2022-12-30 02:34:34浏览次数:45  
标签:console 函数 对象 高级 JS var obj foo

this指向分析

指向

  • 直接调用,指向window

  • 通过对象调用,指向对象

  • call/apply

    总结:跟位置无关,跟调用方式有关。只有在执行的时候this指向才会被确定

绑定规则:

  • 默认绑定

    // 独立函数调用,this指向window
    function foo(){
        console.log(this)
    }
    foo() // window
    
    // 跟位置无关,跟调用方式有关
    var  obj = {
        foo:function(){
            console.log(this)
        }
    }
    var baz = obj.foo
    baz()  // window
    
    // 高阶函数
    function foo1(fn){
        fn()
    }
    foo1(obj.foo) // window
    
    // 严格模式下,独立调用的函数中的this指向的是undefined
    "use strict"
    
    var  obj = {
        foo:function(){
            console.log(this)
        }
    }
    var baz = obj.foo
    baz()  // undefined
    
  • 隐式绑定

    var  obj = {
        foo:function(){
            console.log(this)
        }
    }
    obj.foo() // obj
    
  • 显示绑定

    • call(obj,[item1],[item2])

    • apply(obj,[item1,item2])

      var obj={
          name:'hyf'
      }
      funciton foo(){
          console.log(this)
      }
      
      foo.call(obj) // obj
      
    • bind:创建一个绑定函数BF,怪异函数对象。永久绑定

      var obj={
          name:'hyf'
      }
      funciton foo(){
          console.log(this)
      }
      
      var f = foo.bind(obj,[item1],[item2]...)
      
  • new

    /*
    1. 创建一个新的空对象
    2. 将this指向这个空对象
    3. 执行函数体重的代码
    4. 如果函数没有返回其他对象时,默认返回这个对象
    */
    function Foo(){
        console.log(this)
    }
    var foo = new Foo() // Foo {}
    

内置函数的调用绑定

  • forEach(fn,this): 默认绑定window, 可以通过第二个参数绑定this
  • setTimeout(): this指向window
  • el.coclick: this指向 el

优先级

默认绑定 < 隐式绑定 < 显示绑定 < new绑定。new不可以和apply/call一起使用。bind优先级大于call和apply

null/undefined

function Foo(){
    console.log(this)
}
Foo.call(null) // window, 忽略显示绑定,使用默认规则
Foo.apply(undefined)  // window,忽略显示绑定,使用默认规则

间接函数引用

var obj1 = {
    foo:function(){
        console.log(this)
    }
}
var obj2 = {
    name:'hyf'
}
obj2.foo = obj1.foo
obj2.foo()  // obj2
(obj2.foo = obj1.foo)()  // window

箭头函数

  • 不会绑定this、arguments
  • 不能作为构造函数
var foo = (arg) => {
    // do some thing
}
var obj = (arg) => ({name:33})  // obj = {name:33}

浏览器原理

网页解析过程

  • DNS域名解析
  • 通过IP地址,与服务器三次握手
  • 获取URI资源
  • html下载到浏览器中

浏览器渲染过程

简单渲染过程

详细流程

  • 下载并解析index.html,生成DOM树

  • 下载并解析CSS,生成样式规则,CSSOM,CSS对象模型

  • DOM Tree+ CSSOS 生成渲染树,render Tree

  • 在Reader Tree上计算节点尺寸和位置等信息,进行布局Layout

  • 绘制Paint,将每个frame转为屏幕上的实际的像素点

    link元素不会阻塞DOM Tree 但会阻塞Reader Tree构建

    Reader Tree 与 DOM Tree不是一一对应的,

回流和重绘

  • 回流reflow: 对节点的大小、位置修改重新计算称为回流
    • DOM结构发生改变,添加或删除
    • 改变布局(width,height,padding,font-size)
    • resize(修改了窗口的尺寸)
    • 调用getComputedStyle方法获取尺寸、位置信息
  • 重绘 repaint: 重新渲染
    • 修改背景色,文字颜色,边框颜色,样式

回流一定会引起重绘

  • 如何避免回流

    • 修改样式时尽量一次性修改

    • 尽量避免频繁的操作DOM, DocumentFragment

      const list = document.querySelector('#list')
      const fruits = ['Apple', 'Orange', 'Banana', 'Melon']
      
      const fragment = new DocumentFragment()
      
      fruits.forEach((fruit) => {
        const li = document.createElement('li')
        li.textContent = fruit
        fragment.appendChild(li)
      })
      
      list.appendChild(fragment)
      
    • 尽量避免通过getComputedStyle获取尺寸,位置等信息

    • 对某些元素使用position的absolute或者fixed, 开销相对较少

合成层

  • 默认情况下,标准流中的内容都是被绘制在同一个图层中的
  • 创建新的合成层
    • 3D transforms
    • video、canvas、iframe
    • opacity动画转换时
    • position: fixed
    • will-change:一个实验性的属性,提前告诉浏览器元素可能发生哪些变化
    • animation或transition设置了opcity、transform

script元素与页面解析

遇到script,会停止DOM解析,先加载执行script脚本

  • defer属性:
    • 不会阻塞DOM Tree构建过程。
    • 在DOMContentLoaded之前执行
    • 多个脚本顺序执行
    • 建议放到head中,让浏览器先加载
  • async属性:
  • 不阻塞页面
  • 脚本完全独立
  • 不能保证多个脚本顺序
  • 不能保证在DOMContentLoaded之前或之后执行

JS原理

Webkit = WebCore + JavaScriptCore

V8引擎原理

V8引擎是由C++编写的Google开源高性能JavaScript和WebAssembly引擎,它用于Chrome和Node.js等,V8可以独立运行,也可以嵌入到任何C++应用程序中

V8

  • Parse模块,会将JS代码转为AST(抽象语法树),解释器并不认识JS代码。如果函数没有被调用是不会被转为AST树的
  • lgnition是一个解释器,会将AST转为ByteCode(字节码),同时会搜集TurboFan优化所需的信息(如函数参数类型信息),如果函数只调用一次,lgnition会解释执行ByteCode
  • TurboFan是一个编译器,可以将字节码编译为CPU可以直接执行的机器码
    • 如果一个函数被调用多次,那么会被标记为热点函数,就会经过TurboFan转换为优化的机器码,提高代码的执行性能
    • 但是,机器码实际上也会被还原为ByteCode,这是因为函数在执行中传入的类型改变,之前优化的机器码并不能准确的处理,就会逆转为字节码

官方

JS执行上下文

整体执行流程

  1. js代码执行之前,初始化全局对象Global Object(GO)

    • 该对象在堆内存中创建,所有作用域都可访问

    • 包含Date、Array、String、Number、setTimeout、setInterval

    • 还有window指向自己

  2. 每一个执行上下文都会关联一个VO(Variable Object,变量对象),变量和函数声明都会被添加到这个VO对象中

  3. 全局代码被执行的时候,VO就是GO对象

  4. AO对象:函数执行上下文,会创建一个AO(Activation Object)

    • 这个AO会使用arguments作为初始化,并且初始值是传入的参数
    • 这个AO对象会作为执行上下文的VO来存放变量的初始化
var message = 'aaa'
function bar(){
    var message = 'bb'
}
var num1= 0
var num2= 1
var result = num1+num2

函数会被先创建

函数代码的多次执行

函数在第一次执行完成以后,会被栈移除,AO对象的移除需要看情况(垃圾回收)

作用域和作用域链

函数在创建的时候,作用域链就被确定了,跟调用位置无关

作用域链

作用域链综述:

  • 首先,在代码执行之前,创建GO(Global Object)--VO(Variable Object)对象

    在GO对象中
    message = undefined
    foo = 0x001(指向一个函数对象 Function Object),这个函数对象中包含一些属性,arguments/name/length/[[scopes]]...
    [[scopes]] 中包含0:Global Object
    bar = undefined
    test = undefined
    
  • 代码执行,

    运行 var message = 'global message' 时,GO对象的message被赋值为'global message'
    调用 foo() 时,运行 foo函数代码,此时创建 foo VO(Variable Object)即AO(Activation Object)
    foo AO中 name = undefined , bar = 0x002(指向一个函数对象 Function Object) 这个函数对象中包含一些属性,arguments/name/length/[[scopes]]...
    [[scopes]] 包含 0:Global Object
    返回 bar函数的内存地址 0x002
    将0x002赋值给bar变量
    此时GO中的bar = 0x002
    
  • 代码执行bar()

    调用函数bar(),运行0x002中的代码,创建test=0x003 函数(Function Object)arguments/name/length/[[scopes]]...
    [[scopes]] 中包含0:foo AO, 1:Global Object
    打印name, 寻找name顺序 0--->1
    返回0x003
    将0x003赋值给GO中test变量
    

面试题

// 1.
var n = 100
function foo(){
    n = 200
}
foo()
console.log(n) // 200
// 2
var n = 100
function foo(){
    console.log(n) // undefined
    var n = 200
    console.log(n) // 200
}
foo()
// 3
var n = 100
function foo1(){
    console.log(n)
}

function foo2(){
    var n = 200
    console.log(n) // 200
    foo1()
}
foo2()
/*
分析:
1. 创建GO,n=undefined,foo1=0x001(arguments/name/[[scopes]]:{"0":GO}),foo2=0x002(arguments/name/[[scopes]]:{"0":AO,"1":GO}) AO 包含 n = undefined
2. 调用foo2() 执行foo2代码体中的var n = 200, foo2 AO n = 200,打印200,调用foo1()
3. foo1执行代码,打印n,n的作用域只用GO,所以打印n为100
*/
// 4
var a = 100
funciton foo(){
    console.log(a) // undefined
    return
    var a = 100
}
foo()
// 5
function foo(){
    var a = b = 100
}
foo()
console.log(a) // c is not defined
console.log(b) // 100 , 相当于 var a = 100;  b = 100

内存管理

内存的生命周期

  • 分配申请你所需的内存
  • 使用分配的内存(存放变量,对象等)
  • 不需要使用时,对其进行释放

JS内存分配

  • JS对原始数据类型的内存分配直接在栈空间进行分配
  • JS对复杂数据类型内存的分配会在堆内存中开辟空间,将空间指针地址返回给变量引用

垃圾回收机制 GC(Garbage Collection)

对于那些不再使用的对象,称之为垃圾,需要被回收。Lisp最先提出

引用计数 (Reference counting)

  • 概念

    • 一个对象有一个引用指向它时,对象的引用就+1
    • 当一个对象的引用为0时,这个对象就可以被销毁
  • 缺陷

    • 循环引用

      obj1 = {}             
      obj2 = {}
      obj1.info = obj2
      obj2.info = obj1
      

标记清除 (mark-Sweep)

  • 概念
    • 核心思路:可达性
    • 设置一个根对象,定期从根对象开始,找所有从根开始有引用到的对象,对于那些没有引用到的对象,就认为是不可用的对象
    • 可以很好的解决循环引用的问题

标记整理

  • 与标记清除类似
  • 不同的是,回收期间将保留的存储对象搬运汇集到连续的内存空间,从而整合空闲空间,避免内存碎片化

分代回收

  • 将内存中对象分为新生代、老生代
  • 新创建的对象,都放到新生代,使用结束以后,GC清除垃圾,经过多次回收,还剩下的对象放到老生代中
  • 老生代的检查频率是很低的。

增量收集

  • 如果有很多对象,并且我们试图一次遍历并标记整个对象集,则可能需要一些时间,并在执行过程中带来明显的延迟
  • 所以引擎试图将垃圾收集工作分为几部分来做,然后将这几部分逐一处理,这样会有许多微小的延迟而不是一个很大的延迟

闲时收集

  • GC只会在CPU空闲时尝试运行,以减少可能对代码执行的影响

内存管理

闭包

  • 最早出现在Scheme
  • 如果一个函数,能够访问外层作用域中的变量,那么这个函数和周围环境就是一个闭包
  • 所以,JS中的函数都可以称为闭包函数,因为每当创建一个函数时,这个函数都可以访问外层,如GO中的变量
function createAdder(con){
    function adder(num){
        return con+num
    }
    return adder
}

var adder5 = createAdder(5)  // con固定为5 addr函数中num+5
adder5(10)  // 15 5+10 
var adder10 = createAdder(10)   // con固定为10 addr函数中num+5
adder10(10)  // 20  10+10

内存泄漏与释放

  • 对于某些内存不再使用,需要手动进行释放add10 = null

内存优化

  • AO不使用的属性会被浏览器优化

标签:console,函数,对象,高级,JS,var,obj,foo
From: https://www.cnblogs.com/hyf120/p/17009319.html

相关文章

  • JS对象
    声明对象方式对象字面量varobj1={name:'xx',age:88,}newObject()varobj2=newObject()obj2.name='xx'new自定义类functionPerson(){}varobj3......
  • JS事件
    事件处理三种方案元素上el.onclickwindow.addEventListener(fn)事件流事件冒泡:默认情况下事件是从最内层往外传递的顺序,这个顺序就称为事件冒泡事件捕获:从外层到......
  • 10Javascript高级
    JavaScript面向对象目标:能够说出什么是面向对象能够说出类和对象的关系能够使用class创建自定义类能够说出什么是继承面向对象编程介绍:两大编程思想:面向过程面向对象面向过......
  • JS中回调函数的概念
    概要:Js中回调函数的概念...个人理解:回调函数的定义:将一个函数作为参数的形式传入另一个函数中,那么这个函数就是回调函数,另一个函数可以决定在何时何处调用这个传入的回......
  • JS数据在内存中的存储方式
    概要:Js数据类型在内存中的存储形式......Js数据类型:简单数据类型(基本数据类型):Number、String、Boolean、Undefined、Null复杂数据类型(引用数据类型):Object、Array、Fu......
  • JS中闭包的概念
    概要:Js中闭包的概念...个人理解:js中闭包的定义......
  • JS中的arguments和args
    概要:学习express中间件原理时候遇到的arguments对象和...args形参,从一脸懵逼到简单认识...引言:最近在学习express框架的中间件原理时候遇到了一系列问题,让我总算是明白了......
  • 关于JS中深拷贝和浅拷贝的思考
    概要:对Js数据的深拷贝和浅拷贝做一个总结,加深记忆Js数据类型由基本数据类型和引用数据类型组成,简单数据类型包括(Number、String、Boolean、Undefined、Null);引用数据类型......
  • 4.1 Javascript高级
    JavaScript面向对象目标:能够说出什么是面向对象能够说出类和对象的关系能够使用class创建自定义类能够说出什么是继承面向对象编程介绍:两大编程思想:面向过程面向对象面向过......
  • 前端jsp界面一些固定模板
    <%@pagelanguage="java"contentType="text/html;charset=UTF-8"pageEncoding="UTF-8"%><%@tagliburi="http://java.sun.com/jsp/jstl/core"prefix="c"%><ht......