javascript基础巩固

。_饼干妹妹 提交于 2020-01-18 13:41:12

事件

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

一、事件流

  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指向自己
2. 

commonjs es6

  • 1 输出是值的拷贝,即原来模块中的值改变不会影响已经加载的该值 2 静态分析,动态引用,输出的是值的引用,值改变,引用也改变
  • 1 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)

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!