text: /*
   * Copyright 2016 Google Inc. All rights reserved.
   *
   * Licensed under the Apache License, Version 2.0 (the "License"); you may not
   * use this file except in compliance with the License. You may obtain a copy of
   * the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
   * License for the specific language governing permissions and limitations under
   * the License.
   */
  //https://github.com/GoogleChrome/proxy-polyfill
  export default function proxyPolyfill() {
  	let lastRevokeFn = null;
  	let ProxyPolyfill;
  
  	/**
  	 * @param {*} o
  	 * @return {boolean} whether this is probably a (non-null) Object
  	 */
  	function isObject(o) {
  		return o ? (typeof o === 'object' || typeof o === 'function') : false;
  	}
  
  	/**
  	 * @constructor
  	 * @param {!Object} target
  	 * @param {{apply, construct, get, set}} handler
  	 */
  	ProxyPolyfill = function(target, handler) {
  		if(!isObject(target) || !isObject(handler)) {
  			throw new TypeError('Cannot create proxy with a non-object as target or handler');
  		}
  
  		// Construct revoke function, and set lastRevokeFn so that Proxy.revocable can steal it.
  		// The caller might get the wrong revoke function if a user replaces or wraps scope.Proxy
  		// to call itself, but that seems unlikely especially when using the polyfill.
  		let throwRevoked = function() {};
  		lastRevokeFn = function() {
  			throwRevoked = function(trap) {
  				throw new TypeError(`Cannot perform '${trap}' on a proxy that has been revoked`);
  			};
  		};
  
  		// Fail on unsupported traps: Chrome doesn't do this, but ensure that users of the polyfill
  		// are a bit more careful. Copy the internal parts of handler to prevent user changes.
  		const unsafeHandler = handler;
  		handler = {
  			'get': null,
  			'set': null,
  			'apply': null,
  			'construct': null
  		};
  		for(let k in unsafeHandler) {
  			if(!(k in handler)) {
  				throw new TypeError(`Proxy polyfill does not support trap '${k}'`);
  			}
  			handler[k] = unsafeHandler[k];
  		}
  		if(typeof unsafeHandler === 'function') {
  			// Allow handler to be a function (which has an 'apply' method). This matches what is
  			// probably a bug in native versions. It treats the apply call as a trap to be configured.
  			handler.apply = unsafeHandler.apply.bind(unsafeHandler);
  		}
  
  		// Define proxy as this, or a Function (if either it's callable, or apply is set).
  		// TODO(samthor): Closure compiler doesn't know about 'construct', attempts to rename it.
  		let proxy = this;
  		let isMethod = false;
  		let isArray = false;
  		if(typeof target === 'function') {
  			proxy = function ProxyPolyfill() {
  				const usingNew = (this && this.constructor === proxy);
  				const args = Array.prototype.slice.call(arguments);
  				throwRevoked(usingNew ? 'construct' : 'apply');
  
  				if(usingNew && handler['construct']) {
  					return handler['construct'].call(this, target, args);
  				} else if(!usingNew && handler.apply) {
  					return handler.apply(target, this, args);
  				}
  
  				// since the target was a function, fallback to calling it directly.
  				if(usingNew) {
  					// inspired by answers to https://stackoverflow.com/q/1606797
  					args.unshift(target); // pass class as first arg to constructor, although irrelevant
  					// nb. cast to convince Closure compiler that this is a constructor
  					const f = /** @type {!Function} */ (target.bind.apply(target, args));
  					return new f();
  				}
  				return target.apply(this, args);
  			};
  			isMethod = true;
  		} else if(target instanceof Array) {
  			proxy = [];
  			isArray = true;
  		}
  
  		// Create default getters/setters. Create different code paths as handler.get/handler.set can't
  		// change after creation.
  		const getter = handler.get ? function(prop) {
  			throwRevoked('get');
  			return handler.get(this, prop, proxy);
  		} : function(prop) {
  			throwRevoked('get');
  			return this[prop];
  		};
  		const setter = handler.set ? function(prop, value) {
  			throwRevoked('set');
  			const status = handler.set(this, prop, value, proxy);
  			// TODO(samthor): If the calling code is in strict mode, throw TypeError.
  			// if (!status) {
  			// It's (sometimes) possible to work this out, if this code isn't strict- try to load the
  			// callee, and if it's available, that code is non-strict. However, this isn't exhaustive.
  			// }
  		} : function(prop, value) {
  			throwRevoked('set');
  			this[prop] = value;
  		};
  
  		// Clone direct properties (i.e., not part of a prototype).
  		let propertyNames = Object.getOwnPropertyNames(target);
  
  		/////////用于代理Promise:then方法等
  		if(target instanceof Promise && target.__proto__) {
  			let props = Object.getOwnPropertyNames(target.__proto__);
  			let obj = {};
  			propertyNames.forEach((prop) => {
  				obj[prop] = true;
  			});
  			props.forEach((prop) => {
  				obj[prop] = true;
  			});
  			propertyNames = [];
  			for(let prop in obj) {
  				propertyNames.push(prop);
  			}
  		}
  
  		const propertyMap = {};
  		propertyNames.forEach(function(prop) {
  			if((isMethod || isArray) && prop in proxy) {
  				return; // ignore properties already here, e.g. 'bind', 'prototype' etc
  			}
  			const real = Object.getOwnPropertyDescriptor(target, prop);
  			const desc = {
  				enumerable: !!(real && real.enumerable),
  				get: getter.bind(target, prop),
  				set: setter.bind(target, prop),
  			};
  			Object.defineProperty(proxy, prop, desc);
  			propertyMap[prop] = true;
  		});
  
  		// Set the prototype, or clone all prototype methods (always required if a getter is provided).
  		// TODO(samthor): We don't allow prototype methods to be set. It's (even more) awkward.
  		// An alternative here would be to _just_ clone methods to keep behavior consistent.
  		let prototypeOk = true;
  		if(Object.setPrototypeOf) {
  			Object.setPrototypeOf(proxy, Object.getPrototypeOf(target));
  		} else if(proxy.__proto__) {
  			proxy.__proto__ = target.__proto__;
  		} else {
  			prototypeOk = false;
  		}
  		if(handler.get || !prototypeOk) {
  			for(let k in target) {
  				if(propertyMap[k]) {
  					continue;
  				}
  				Object.defineProperty(proxy, k, {
  					get: getter.bind(target, k)
  				});
  			}
  		}
  
  		// The Proxy polyfill cannot handle adding new properties. Seal the target and proxy.
  		Object.seal(target);
  		Object.seal(proxy);
  
  		return proxy; // nb. if isMethod is true, proxy != this
  	};
  
  	ProxyPolyfill.revocable = function(target, handler) {
  		const p = new ProxyPolyfill(target, handler);
  		return {
  			'proxy': p,
  			'revoke': lastRevokeFn
  		};
  	};
  
  	return ProxyPolyfill;
  }