重构new apply bind call

1.重构new

function Fn() {
 /*
      1.要有一个对象
        // 方案1
          let obj = {}
          obj.__proto__ = FC.prototype
        // 方案2
          let obj = Object.create(FC.prototype)
      2.执行此函数,解决this的指向  let ret = FC.apply(obj)
      3.判断函数执行的返回值,是基本类型或无返回值则返回对象,有引用类型,则返回指定的
    */
}
let f1 = new Fn()

// ===============================================================
function _new(Construct, ...args) {
  // 创建一个实例对象(创建Construct类的实例,让其 对象.__proto__ = Construct.prototype)
  // obj.__proto__ = Construct.prototype
  let obj = Object.create(Construct.prototype)
  // 把函数执行,让this指向实例对象
  let ret = Construct.call(obj, ...args)
  //  处理返回值,引用类型,直接返回引用类型的值
  if (ret !== null && /^(object|function)$/.test(typeof ret)) {
    return ret
  }
  return obj
}

function Fn(name) {
  this.name = name
  this.age = function () {
    console.log('方法===' + this.name)
  }
}
let f1 = _new(Fn, '张三')
f1.age()

2.重构call

Function.prototype.myCall = function (ctx, ...params) {
  // 参数可以为 undefined或null
  ctx = ctx == null ? window : ctx
  // 需要保证ctx必须是对象类型的值:因为只有对象才能设置属性
  ctx = !/^(object|function)$/.test(typeof ctx) ? Object(ctx) : ctx

  let self = this
  let ret = null
  // 新增的属性名保证唯一性,防止污染原始对象中的成员数据
  let functionName = Symbol('functionName')
  // 给对象添加属性
  ctx[functionName] = self
  // 执行方法
  ret = ctx[functionName](...params)
  // 删除自定义属性
  delete ctx[functionName]
  return ret
};

function fn(x, y) {
  console.log(this, x, y)
}
let obj = {
  name: '张三'
}
fn.myCall(obj, 2, 3)

3.重构apply

 function fn1(a, b, c, ...d) {
      console.log(this, a, b, c, d)
      return '你的姓名为:' + this.name
    };
    var obj = { name: 2222, fn: 'abc' };

    // 自定义一个apply方法,强制改变this指向
    Function.prototype.myApply = function (Ctx, args) {
      if (!Array.isArray(args)) throw new TypeError('参数2必须是数组');
      // == 为null,判断是否为 null或undefined
      // console.log(Ctx == null)
      Ctx = Ctx == null ? window : (typeof Ctx != 'object' ? Object(Ctx) : Ctx)
      // 给传入的对象添加一个属性
      // 给自定义的属性添加一个随机名称
      const methodName = Symbol();
      // Ctx.fn = this
      Ctx[methodName] = this
      // 执行
      // let ret = Ctx.fn()
      let ret = Ctx[methodName](...args)
      // 删除
      delete Ctx[methodName]
      // 返回
      return ret;
    }

4.重构bind

Function.prototype.myBind = function myBind(ctx, ...params) {
  let self = this
  return function (...args) {
    self.apply(ctx, [...params, ...args])
  }
};

var obj = { id: 1 }
function fn(...args) {
  console.log(this, args)
}
btn.onclick = fn.bind(obj, 1, 2)

5.重构instanceof

es5的检测原理

检测构造函数的prototype是否出现在实例的__proto__上

es6的检测原理

构造函数 Symbol.hasInstance属性

function _instanceof(obj, FC) {
      // 如果不是对象则抛异常
      if (typeof obj !== 'object') throw new TypeError('必须是引用类型!');
      // 对象不能是函数
      if (typeof obj === "function") return false;
      // obj为null 或 undefined 为 false
      if (obj == null) return false;

      // 得到当前FC原型
      var prototype = FC.prototype;
      if (!prototype) return false;

      // 兼容性判断处理 环境支持es6  ==> typeof Symbol 暂时性死区,es6的判断
      if (typeof Symbol === "function") {
        // 返回true/false
        var insFn = FC[Symbol.hasInstance];
        if (typeof insFn === "function") { // 可以被调用执行
          return insFn.call(FC, obj)  
        }
      }
      // 得到对象的原型 ---  针对于老版本浏览器,es5的判断
      // var proto = obj.__proto__
      var proto = Object.getPrototypeOf(obj)
      //console.log(proto.__proto__) return false
      while (1) {
        if (proto === null) return false;
        if (proto === prototype) return true;
        // proto = proto.__proto__
        proto = Object.getPrototypeOf(proto)
      }
    }

6.代理拦截

6.1defineProperty

ES5 提供了 Object.defineProperty 方法,该方法可以在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回这个对象。Object.defineProperty无法监听数组变化。

var obj = {
    test:"hello"
}
//对象已有的属性添加特性描述
Object.defineProperty(obj,"test",{
    // 能不能被配置(删除)
configurable:true | false,
// 是否可枚举
    enumerable:true | false,
value:任意类型的值,
// 是否可写,此配置和 get/set不能同时存在
writable:true | false,
get(){},
set(value){}
});

// ===============================================
var data = {
  name: '张三'
}

function observer(data) {
  if (typeof data !== 'object') return data
  for (let key in data) {
    defineReactive(data, key, data[key])
  }
}

function defineReactive(target, key, value) {
  observer(value)
  Object.defineProperty(target, key, {
    get() {
      return value
    },
    set(newVal) {
      if (value !== newVal) {
        value = newVal
        update(key, value)
      }
    }
  })
}

function update(key, value) {
  document.querySelectorAll(`[v-bind="${key}"]`).forEach(el => {
    if (el.tagName === 'INPUT') {
      el.value = value
    } else {
      el.innerHTML = value
    }
  })
};
// 监听
observer(data);


// 初始化
document.querySelectorAll('[v-model]').forEach(el => {
  el.addEventListener('keyup', function () {
    let prop = this.getAttribute('v-model')
    data[prop] = this.value
  })
})

6.2 Proxy

Proxy是es6提供的新的api,Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。
(1)Proxy可以直接监听对象而非属性
(2)Proxy直接可以劫持整个对象,并返回一个新对象,不管是操作便利程度还是底层功能上都远强于Object.defineProperty。
(3)Proxy可以直接监听数组的变化
(4)Proxy有多达13种拦截方法,不限于apply、ownKeys、deleteProperty、has等等是Object.defineProperty不具备的。

const obj = { name: "张三" };

const proxy = new Proxy(obj, {
  get(target, key) {
    return target[key];
  },
  set(target, key, value) {
    console.log(target, key, value)
    target[key] = value;
    return true;
  }
});
proxy.age = 10;
console.log(proxy, obj);

字符串截取
const news = [
  {
    title: "海外网深一度:气候危机“逼近灾难临界值”,中国行动振奋世界"
  },
  {
    title: "小区不准外卖员入内,杭州一外卖小哥回家被保安拦下!民警到场调解,小哥情绪崩溃"
  },
  {
    title: "网传浙江慈溪上林中学一女生教室内被多次扇耳光 当地回应:已去处置"
  }
];
const newsProxy = new Proxy(news, {
  get(target, key) {
    let title = target[key]['title'];
    target[key]['title'] = title.length > 10 ? title.substr(0, 10) + '...' : title
    return target[key]
  }
});

console.log(newsProxy[0])

双向绑定
let obj = {
  name: '张三',
}

const proxyHandler = {
  get(target, key) {

    if (typeof target[key] === "object") {
      return new Proxy(target[key], proxyHandler)
    }

    return target[key]
  },
  set(target, key, value) {
    let oldValue = target[key]
    if (oldValue !== value) {
      target[key] = value
      update(key, value)
      return true
    }
  }
}

let proxy = new Proxy(obj, proxyHandler)

function update(key, value) {
  document.querySelectorAll(`[v-bind="${key}"]`).forEach(el => {
    if (el.tagName === 'INPUT') {
      el.value = value
    } else {
      el.innerHTML = value
    }
  })
}


// 初始化时
document.querySelectorAll('[v-model]').forEach(el => {
  el.addEventListener('keyup', function () {
    let prop = this.getAttribute('v-model')
    proxy[prop] = this.value
  })
})

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值