JS学习

93 阅读4分钟

写在文章的开头,好记性不如烂笔头,干什么事情都是贵在坚持,为了提升自己的前端水平,我也看了不少文章和知识,可是到头来总是转头忘,这段时间看了些文章,也分享了很多知识,但是总是感觉不足,虽然自己为了生活的事情很烦恼,但是也不能停下来学习的脚步,从现在开始坚持一个星期写三篇文章,完成文章最终目的是坚持自己的学习之路,学会总结,无论文章是初级还是高级,也是一个坚持的理由## js学习

执行上下文

1.什么是执行上下文,一般有两类包括全局执行上下文,函数执行上下文

2.全局执行上下文由浏览器创建,一般指window

3.执行上下文栈,也叫做调用栈,相当于一个数组,执行先进后出的特性,也就是执行上下文栈中最后一个都是全局执行上下文

4.执行上下文的创建分为创建和执行阶段

创建阶段分为三件事情:

  • 创建Scope chain

  • 创建VO/AO(variables, functions and arguments)

  • 设置this的值

    创建 VO的时候,变量,函数参数,函数申明

    function foo(a) {
      var b = 2;
      function c() {}
      var d = function() {};
    
      b = 3;
    
    }
    
    foo(1);
    

    vo

    vo = {
    
    	arguments:{
    	   0:1
          length:1
    	},
      a:1,
      b:undefined,
      c:functin c(){},
      d:undefined
    }
    

变量对象会包括:

  1. 函数的所有形参 (如果是函数上下文)
    • 由名称和对应值组成的一个变量对象的属性被创建
    • 没有实参,属性值设为 undefined
  2. 函数声明
    • 由名称和对应值(函数对象(function-object))组成一个变量对象的属性被创建
    • 如果变量对象已经存在相同名称的属性,则完全替换这个属性
  3. 变量声明
    • 由名称和对应值(undefined)组成一个变量对象的属性被创建;
    • 如果变量名称跟已经声明的形式参数或函数相同,则变量声明不会干扰已经存在的这类属性

作用域链

函数的作用域在函数定义的时候就决定了

查找变量的时候会先从当前执行上下文变量对象中寻找,如果没有就会在父级的执行上下文变量对象中寻找,一直到全局执行上下文,由多个执行上下文的变量对象构成的链表就叫做作用域链

闭包函数

MDN 对闭包的定义为:

闭包是指那些能够访问自由变量的函数。

那什么是自由变量呢?

自由变量是指在函数中使用的,但既不是函数参数也不是函数的局部变量的变量。

由此,我们可以看出闭包共有两部分组成:

闭包 = 函数 + 函数能够访问的自由变量

var scope = "global scope";
function checkscope(){
    var scope = "local scope";
    function f(){
        return scope;
    }
    return f;
}

var foo = checkscope();
foo();

分析此文件运行流程

1.执行代码,创建全局执行上下文,全局执行上下文压入执行上下文栈

ECStack = [
		globalContext
]

2.全局执行上下文(初始化)(创建变量对象,创建作用域链,指定this)

globalContext = {
	VO:[global],
  Scope:[globalContext.VO],
  this:globalContext.VO
}

创建变量对象:

 vo = {
		scope:undefined,
		checkscope:function f(){}
   	foo:undefined
}

3.初始化的同时,checkscope函数被创建,保存作用域链到函数内部属性[[scope]]

checkscope.[[scope]] = [globalContext.VO]

4.执行checkscope函数,创建checkscope函数执行上下文,压入执行上下文栈

(1)复制函数属性[[scope]]属性创建作用域链

​ (2) 创建VO,使用arguments创建活动对象

(3)初始化活动对象,加入形参,函数申明,变量申明

(4) 将活动对象压入checkscope的作用域链

5.在创建变量对象的时候,函数申明的时候,checkscope的作用域链保存给f函数内部属性[[scope]]

f.[[scope]] = [checkscopeContext.VO,global.VO]

6.执行f函数,创建f的函数上下文,推入执行上下文栈

7.f的函数上下文初始化,创建变量对象,将变量对象压入f的作用域链

fcontext={
  VO:{
    arguments:{
      lenght:0
    }
    c:function(){}
		d:undefined
  },
  scope:[fContext.VO,checkscopeContext.VO,global.VO]
	this:fcontext.VO
}

原型

函数中有prototype属性,就是其函数原型对象,

function Person() {

}
var person = new Person();
console.log(person.__proto__ === Person.prototype); // true

person实例的_ _proto__指向的是Person.prototype

Person.prototype.constructor 指的是Person

手写call

call实际就是指定this,和若干值来调用函数方法

var obj = {
	value:"测试"
}
function bar(){
  console.log(this.value)
}
 bar.call(obj)
//call的正常使用

/*var obj = {
  value:测试
  function fn(){
    console.log(this.value)
  }
}
obj.bar()*/
//实际上是为了这个实现,思路就是给这个对象一个bar属性上有这个方法

Function.prototype.copyCall = function(obj){
  obj.fn = this//此时这个指的前面引用方法
  obj.fn(argument[1])
  delete foo.fn
}
 bar.copyCall(obj)

防抖

事件触发后多少秒才能触发下一次事件,如果在规定时间再次触发,则会重置时间,才能触发事件

function debounce(fn,timeout){
  let task
  return function(){
    let context = this
    clearTimeout(task)
    task = setTimeout(()=>{
      fn.apply(context,arguments)
      //fn() 这样写,this指向不是事件绑定的节点 所以使用fn.apply调用
    },timeout)
  }
}

function debounceAtTime(fn,timeout,immediately){
  let task
  return function(){
    clearTimeout(task)
    !task && fn()
    task = setTimeOut(()=>{
    	task = null
    },timeout)
  }
}

节流

function throttle(fn,wait){
  let prev = 0
  return function(){
    now = new Date()
    if(now - prev > wait){
      fn()
      prev = now
    }
  }
}