Javascript设计模式 -- 代理模式

295 阅读1分钟

代理模式

由于一个对象不能直接引用(或者不方便引用)另一个对象,所以需要通过代理对象在这俩个对象之间起中介的作用。

虚拟代理

虚拟代理并不会减少重复的代码和提高对象的模块性,只有在资源创建或报错有很大开销,需要通过代理来控制他们的创建时间和方式。

图片懒加载中

<img src="lazy.jpg" data-src="xxxx.jpg" />

远程代理

跨域请求:通过node或者别的服务代理到

// koa代理
var proxy = require('koa2-proxy');
// 转发请求到指定host
proxy.when('/api', function(ctx) {
    ctx.request.host = 'www.test.com';
    ctx.request.protocol = 'http';
});

再看Vue源码中的代理

const app = new Vue({
  el: '#app',
  data:{
    message: 'Hello Vue!'  
  }
})
console.log(app._data.message) // Hello Vue!
console.log(app.message);  // Hello Vue!

我们可以直接通过 '.' 获取到data中的属性,Vue是怎么实现的呢?

const sharedPropertyDefinition = {
  enumerable: true,
  configurable: true,
  get: noop,
  set: noop,
} 
function proxy(target, sourceKey, key) {
  sharedPropertyDefinition.get = function proxyGetter(){
    return this[sourceKey][key];
  }; 
  sharedPropertyDefinition.set = function ProxySetter(val){
    this[sourceKey][key] = val;  
  }
  Object.defineProperty(target, key, sharedPropertyDefinition);
}

proxy(vm, '_data', key);

具体代码

function initData(vm) {
  var data = vm.$options.data;
  // 将data参数赋值给 vm._data
  data = vm._data = typeof data === 'function'
    ? getData(data, vm)
    : data || {};
  //xxx
  var keys = Object.keys(data);
  var props = vm.$options.props;
  var methods = vm.$options.methods;
  var i = keys.length;
  // 遍历data
  while (i--) {
    var key = keys[i];
    
    // 判断是否在methods 和props定义过,提示错误
    if (methods && hasOwn(methods, key)) {
      warn(
        ('Method "' + key + '" has already been defined as a data property.'),
        vm,
      );
    }
    
    if (props && hasOwn(props, key)) {
      warn(
        'The data property "' + key + '" is already declared as a prop. ' +
        'Use prop default value instead.',
        vm,
      );
    } else if (!isReserved(key)) {
          
      proxy(vm, '_data', key);
    }
  }
}