js 工作中做的笔记

事件

事件:指的是文档或者浏览器窗口中发生的一些特定交互瞬间。我们可以通过侦听器(或者处理程序)来预定事件,以便事件发生的时候执行相应的代码。

事件流

  1. 事件流:描述的是在页面中接受事件的顺序
  2. 事件冒泡:由最具体的元素接收,然后逐级向上传播至最不具体的元素的节点(文档)
  3. 事件捕获:最不具体的节点先接收事件,而最具体的节点应该最后接收事件
  4. 先捕获后冒泡假如我们点击一个div, 实际上是先点击document,然后点击事件传递到div,而且并不会在这个div就停下,div有子元素就还会向下传递,最后又会冒泡传递回document
  5. 兼容触发DOM上的某个事件时,会产生一个事件对象event 只有在事件处理程序执行期间,event对象才会存在,一旦事件处理程序执行完毕,event对象就会被销毁

事件处理

  • HTML事件处理:直接添加到HTML结构中
  • DOM0级事件处理:把一个函数赋值给一个事件处理程序属性,以这种方式添加的事件处理程序会在事件流的冒泡阶段被处理
 //DOM0的事件,对于同一个dom节点而言,只能注册一个,后边注册的 同种事件 会覆盖之前注册的
 var btn5 = document.getElementById('btn5');
 btn5.onclick=function(){
    console.log(this.id);//btn5   
 };
  • DOM2级事件处理:
addEventListener("事件名","事件处理函数",布尔值)
false时表示在事件冒泡阶段调用事件处理程序,一般建议在冒泡阶段使用,特殊情况才在捕获阶段;
true:事件捕获
false:事件冒泡
removeEventListener();

eval

// eval 方法可以执行执行过的js脚本代码
<script id="a">
    console.log("aaa")
</script>
<script>
    eval(document.getElementById("a").innerText)
</script>

原型链

// instanceof检测左侧的__proto__原型链上,是否存在右侧的prototype原型
1. 一个没有原型的构造函数的construct指向自己

commonjs es6 模块的区别

  • 输出是值的拷贝,即原来模块中的值改变不会影响已经加载的该值 2 静态分析,动态引用,输出的是值的引用,值改变,引用也改变
  • this 指向当前模块 2 this 指向undefined

es6 note

// 1. let 没有预编译,不存在变量提升
// 2. 不可以重复定义变量
// 3  箭头函数没有 arguments
// 4  箭头函数不能做构造函数
let file_name = "huahua.png"
//  包含字符串
console.log(file_name.includes("hua"))
//  string 是以谁开头 
console.log(file_name.startsWith("hua"))
//  结尾 
console.log(file_name.endsWith("png"))
function test(){
  // arguments 是类数组对象 不是数组 
  let arg = arguments;
  // let res = Array.prototype.slice.apply(arg)
  //  1. 把类数组变成数组 2. 把字符串变成数组 
  let res = Array.from(arg)
}

Proxy

 var person = {
        name: "tom",
        age: 23
    };
    var handler = {
        get: function(target, key, receiver){
            console.log(receiver)
            console.log(this) // handler
            return target["name"];
        },
        set: function(target, key, value , receiver){
            target[key] = value
            return true;
        },

        /**
         * @name  in 操作的钩子
         */
        has: function(target, prop){
            console.log("--proxy-has")
            console.log(target)
            console.log(prop)
            return true;
        },
        // 当读取代理对象的原型时
        getPrototypeOf(target) {
            console.log(target)
        },

        /**
         * @name 用于拦截对对象的 Object.defineProperty() 操作
         * @param target
         * @param property
         * @param descriptor
         * @returns {boolean}
         * @eg
         * Object.defineProperty(proxy, "sex", {
         *       value:"male",
         *       writable:true,      // 可以被覆盖
         *       enumerable: true    //可以被遍历
         *   })
         */
        defineProperty(target, property, descriptor){
            console.log(target, property, descriptor)
            // 必须返回一个布尔值,否则报错
            return true;
        },

        /**
         * @name  拦截对象的delete属性操作
         * @param target
         * @param property
         * @returns {boolean}
         * @eg delete proxy.name;
         */
        deleteProperty(target, property){
            console.log(property)
            return true;
        }
    }
    var proxy = new Proxy(person,handler);

    console.log(name in proxy)

bind 深入理解

/*
存在this指向的情况 
1 函数嵌套函数
2 闭包
3 构造函数
bind只是返回一个函数,不执行 
Note
1. 事件处理,回调函数最好单独处理,便于维护
2. 构造函数不执行就就是普通的函数,否则就生成指向实例的this
3. 构造函数bind, 会对象实例化的this,就不是bind的this
*/
function Dog(){
   console.log(this)
   console.log(this.food)
}
let context = {
   name: 'context1', food: "banana"
}
let Dog1 = Dog.bind(context);
let dog1 = new Dog1()

console.log(Function.prototype.bind().name)// bound
Function.prototype.binding = function () {
            const _this = this;
            const [context, ...args] = Array.from(arguments)
            // 圣杯模式解决prototyoe问题
            const tempFn = function () {}
            const bound = function (args1) {
                // if no args the args1 is undefined will throw error 
                args1 = args1 || [];
                args1 = Array.from(args1);

                // 这里的return是模拟函数里的return
                return _this.apply(this instanceof _this ? this : context, [...args, ...args1])
            }
            tempFn.prototype = _this.prototype;
            bound.prototype = new tempFn();
            return bound;
}

代理模式

 var data = { id: 'hua', val: ''}
      function bindDomToData(data){
        const dom = document.getElementById(data.id);
        function handleChange(){
          data.val = this.value;
        }
        dom.addEventListener("input", handleChange)
      }

      bindDomToData(data)
     
      const handler = {}
      handler.set = function (target, key, value, receiver) {
          document.getElementById(data.id).value = value;
          return Reflect.set(target, key, value, receiver);
      }
      handler.get = function (target, key, receiver) {
         return target[key]
      }
      var proxy = new Proxy(data,handler);

      document.getElementById("click").onclick = function(){
        proxy.val =  Math.random().toFixed(6)
      }

reflect

有这么一个全局对象,上面直接挂载了对象的某些特殊方法,这些方法可以通过Reflect.apply这种形式来使用,当然所有方法都是可以在 Object 的原型链中找到的

函数式编程

javascript是函数式编程和面向对象编程的混编,可扩展性强,
函数式编程属于 生命式编程的范畴,
函数式编程的特点是函数的参数可以是函数,返回值也可以是函数,
高阶函数,如下

var  shout = function(out){
  var random = (Math.random() * 321).toFixed(3);
  return function(message){
    out(`#${random} ${message.toUpperCase()}!!!`)
  }
}
var out = function(mes){
   console.log(mes)
}
var tell = shout(out)
tell("I am a cool boy")

function compute(obj){
 return {
   add: function(){
       return obj.a + obj.b;
   },
   minus: function(){
       return obj.a - obj.b;
   },
   multiply: function(){
      return obj.a * obj.b;
   }
}

var data = compute({a : 10 , b : 2})
console.log(data.add())
console.log(data.minus())
console.log(data.multiply())
    
手写instanceof
function _instanceof(A, B) {
    var O = B.prototype;// 取B的显示原型
    A = A.__proto__;// 取A的隐式原型
    while (true) {
        //Object.prototype.__proto__ === null
        if (A === null)
            return false;
        if (O === A)// 这里重点:当 O 严格等于 A 时,返回 true
            return true;
        A = A.__proto__;
    }
}
</pre>
深拷贝
   function deepClone(data) {
        if(typeof data === "object" && data !== null){
            var type = data.constructor;
            var result = new type();
            for (var key in data) {
                if (data.hasOwnProperty(key)) {
                    result[key] = deepClone(data[key]);
                }
            }
            return result;
        }
        return data;
    }
数组降维
var arr = [1, 2, [3]];
var res = Array.prototype.concat.apply([], arr);
console.log(res);
var arr2 = [1];
console.log(111);
console.log(arr2.concat(11));

// es6 
let flatten = arr => arr.reduce((begin,current)=>{
        Array.isArray(current)?
        begin.push(...flatten(current)):
        begin.push(current);
        return begin
    },[])
tofixed返回string
let aa = 10937843.44;
console.log(typeof aa.toFixed(3));
函数声明和函数表达式
let test = function aa(){} //  这是一个表达式,表达式忽略名字的 
let test1 = function(){}
console.log(test) 
console.log(test.name) // aa 
console.log(test1.name) //test1 
console.log(aa)
函数形参和实参
function tmp(a,b){
  console.log(tmp.length) // 2 表示函数形参的个数 
}
tmp(1)
function sum(a,b,c){
  a = 11;
  console.log(arguments[0]) // 形参和实参映射关系(两个都存在才映射)
  c = 2;
  console.log(arguments[2]) // undefined  
}
sum(1,2)
js 执行顺序
// - 1 语法分析
// - 2 预编译 发生在函数执行的前一刻 
// 函数声明整体提升,变量只是声明提升 
// 预编译的过程(主要是读变量声明)
// 1. 创建AO对象(Active Object) 
// 2. 查找函数形参及函数内变量声明,形参名及变量名作为AO对象的属性,值为undefined 
// 3. 实参形参相统一,实参值赋给形参 
// 4. 查找函数声明,函数名作为AO对象的属性,值为函数引用
全局的就是GO 就是window 
function test(){
  console.log(b)
  if(a){
    var b = 10; // 不要管if ,预编译看到声明就处理 
   }
}

// - 3  解释执行 

数字

// js里的数字都是64位,0-51是数字,52-63是指数,64位是符号位
// 位运算是用32位进行二进制执行

// toString 可以进制转换 
var a = 10;
a.toString(2) // "1010"

正则

默认是贪婪匹配,就是尽可能多的匹配

// 开启懒惰匹配 

var reg = /\d+/g;
var reg1 = /\d+?/g;
var str = '11aa22';
console.log(str.match(reg)) // [ '11', '22' ]
console.log(str.match(reg1))// [ '1', '1', '2', '2' ]


继承

  • 原型链继承
  /**
   * @title 原型链继承
   *
   * @good 简单明了,容易实现
   * @good 实例是子类的实例,实际上也是父类的一个实例
   * @good 父类新增原型方法/原型属性,子类都能访问到
   *
   * @bad 所有子类的实例的原型都共享同一个超类实例的属性和方法
   * @bad 无法实现多继承
   */
  function A() {
    this.name = 'A'
  }

  A.prototype.list = []

  const a = new A()
  
  function B() {
    this.name = 'B'
  }

  B.prototype = new A();

  const b = new B();

  console.log(b)

  • 构造继承
  /**
   * @title 构造继承
   *
   * @good 解决了父类属性,子类共享问题
   * @good 可以多继承,call多个
   * @good 可以向父类传参数
   *
   *
   * @bad 无法继承原型链上的属性和方法
   * @bad 实例并不是父类的实例,只是子类的实例 cat instance of Animal 是false
   * @bad 无法实现函数复用,每个子类都有父类实例函数的副本,影响性能
   */
  function C() {
    A.call(this)
    this.say = ';llllll'
  }

  const c = new C()

  console.log(c)

  • 经典继承
function create(obj) {
    if(Object.create) {
    return Object.create(obj);  
    } else {
    function F(){};
    F.prototype = obj;
    return new F();
    } 
}

vue2

vdom diff

简单的diff,遍历newVnode,每一个在oldVnode里find,找到了,移动位置或者修改子节点,没找到是新增节点,最后在oldVnode里没有被处理的删掉

// base on snabbdom
// 同级比较 

vue2 响应式实现

// vue2 缺点
// 默认会递归
// 数组改变length无效
// 对象不存在的属性,无法被拦截

let OldProto = Array.prototype;
let proto = Object.create(OldProto);

['push', 'shift', 'unshift'].forEach(item => {
  // 函数劫持 函数重写
  proto[item] = function () {
    OldProto[item].call(this, ...arguments)
    updateView()
  }
});

function updateView() {
  console.log("udpate")
}

function observer(target) {
  if(typeof target !== 'object' || !target){
    return target;
  }
  if(Array.isArray(target)){
    target.__proto__ = proto;
    target.forEach(item => {
      observer(item)
    })
  }else {
    for(let key in target){
      defineReactive(target, key, target[key])
    }
  }
}

function defineReactive(target, key, value) {
  // 递归
  observer(value);
  Object.defineProperty(target, key, {
    get(){
      return value;
    },
    set(newValue){
      if(newValue !== value){
        observer(newValue)
        updateView();
        value = newValue;
      }
    }
  });
}

let data = {
  name: 'huahua',
  age: [1,2,3]
};
observer(data);

data.name = 'lala'
data.age.push(88)

拖拽优化

import $ from "jquery";
import state from "../state"

const doc = document;
let E_SIZER = {};
let ELEMENT = null;
let start = false;

export default function initDrag() {

  function moveFn(e) {
    if(start){
      e.stopPropagation()
      e.preventDefault()
      let moveX = e.clientX - E_SIZER['distX'];
      let moveY = e.clientY - E_SIZER['distY'];
      E_SIZER['moveX'] = moveX
      E_SIZER['moveY'] = moveY
      ELEMENT.style.transform = `translate3d(${moveX}px, ${moveY}px, 1px)`
    }
  }

  $("#onlineReport").on("mousedown", '.draggable', function (event) {
    console.log("drag-start...");
    if ($(event.target).hasClass("draggable")) {
      start = true;
      E_SIZER = {}
      ELEMENT = event.target;
      event.stopPropagation()
      event.preventDefault()
      let matrix3dReg1 = /^matrix3d\((?:[-\d.]+,\s*){12}([-\d.]+),\s*([-\d.]+)(?:,\s*[-\d.]+){2}\)/;
      let matrixReg = /^matrix\((?:[-\d.]+,\s*){4}([-\d.]+),\s*([-\d.]+)\)$/;

      let matrix3dSourceValue = $(event.target).css('transform');
      let matrix3dArrValue = matrix3dSourceValue.match(matrix3dReg1) || matrix3dSourceValue.match(matrixReg);

      // 记录鼠标点击时的坐标
      E_SIZER['clientX'] = event.clientX;
      E_SIZER['clientY'] = event.clientY;

      // 记录 matrix 解析后的 translateX & translateY 的值
      E_SIZER['targetX'] = matrix3dArrValue[1];
      E_SIZER['targetY'] = matrix3dArrValue[2];

      // 计算坐标边界巨鹿
      E_SIZER['distX'] = E_SIZER['clientX'] - E_SIZER['targetX'];
      E_SIZER['distY'] = E_SIZER['clientY'] - E_SIZER['targetY'];

      // 绑定 mousemove 事件
      doc.addEventListener('mousemove', moveFn, false)
    }

  });


  doc.addEventListener('mouseup', function (e) {
    if(start){
      e.stopPropagation()
      e.preventDefault()
      doc.removeEventListener('mousemove', moveFn)
      let item = state.currentData[state.current.item];
      item.moveX = E_SIZER.moveX;
      item.moveY = E_SIZER.moveY;
      start = false;
    }
  }, false);

}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值