//获取原型环境代码
let getProtoEnvCode = function getProtoEnvCode(proto,instanceObj) {
//proto:原型函数
//instanceObj:实例对象,可选参数 传的话会添加默认值
let code = "";
let protoName = proto.name;
//添加注释
code += `// ${protoName}对象\r\n`;
//定义原型
code += `${protoName} = function ${protoName}(){`;
try {
new proto;
} catch (e) {
code += `return ldvm.toolsFunc.throwError('${e.name}','${e.message}');`;
}
code += `}\r\n`;
//保护原型
code += `ldvm.toolsFunc.safeProto(${protoName},"${protoName}");\r\n`;
//设置原型链
let protoObj = proto.prototype;
let proto_protoName = Object.getPrototypeOf(protoObj)[Symbol.toStringTag];//原型对象的原型的名称,父级原型名称
if(proto_protoName !== undefined){//在存在父级的情况下设置原型
code += `Object.setPrototypeOf(${protoName}.prototype,${proto_protoName}.prototype);\r\n`;
}
//设置原型属性
for(const key in Object.getOwnPropertyDescriptors(proto)){
if(key === "arguments" || key === "caller" || key === "length" || key === "name" || key === "prototype"){
continue;
}
let descriptor = getDescriptor(proto,key,protoName,protoName,instanceObj);
code += `ldvm.toolsFunc.defineProperty(${protoName},"${key}",${descriptor});\r\n`;
}
//设置原型对象的属性
for(const key in Object.getOwnPropertyDescriptors(proto.prototype)){
if(key === "constructor"){
continue;
}
let descriptor = getDescriptor(proto.prototype,key,`${protoName}.prototype`,protoName,instanceObj);
code += `ldvm.toolsFunc.defineProperty(${protoName}.prototype,"${key}",${descriptor});\r\n`;
}
console.log(code);
copy(code);
//return code;
}
//获取实例对象的环境代码
let getObjEnvCode = function getObjEnvCode(obj,objName,instanceObj){
//obj 实例对象
//objName 实例对象名称
//instanceObj 实例对象 传输的话设置默认值
let code = "";
//添加注释
code += `// ${objName}对象\r\n`;
//定义对象
code += `${objName} = {}\r\n`;
//设置原型
let protoName = Object.getPrototypeOf(obj)[Symbol.toStringTag];
if(protoName != undefined){
code += `Object.setPrototypeOf(${objName},${protoName}.prototype);\r\n`;
}
//设置对象属性
for(const key in Object.getOwnPropertyDescriptors(obj)){
let descriptor = getDescriptor(obj,key,objName,objName,instanceObj);
code += `ldvm.toolsFunc.defineProperty(${objName},"${key}",${descriptor});\r\n`;
}
console.log(code);
copy(code);
//return code;
}
//获取属性描述符
let getDescriptor = function getDescriptor(obj,prop,objName,protoName,instanceObj) {
let descriptor = Object.getOwnPropertyDescriptor(obj,prop);
let configurable = descriptor.configurable;
let enumerable = descriptor.enumerable;
let code = `{configurable:${configurable}, enumerable:${enumerable}, `;
if(descriptor.hasOwnProperty("writable")){
let writable = descriptor.writable;
code += `writable:${writable}, `;
}
if(descriptor.hasOwnProperty("value")){
let value = descriptor.value;
if(value instanceof Object){
if(typeof value === "function"){
code += `value:function(){return ldvm.toolsFunc.dispatch(this,${objName},"${protoName}","${prop}",arguments);}`;
}else{
//需要关注
console.log("需要额外关注",value);
//JSON.stringify(value)//如果不是非循环引用可以这样转化值
code = `value:{}`;
}
}else if(typeof value === "symbol"){
code += `value:${value.toString()}`;
}else if(typeof value === "string"){
code += `value:"${value}"`;
}else{
code += `value:${value}`;
}
}
if(descriptor.hasOwnProperty("get")){//有默认值
let get = descriptor.get;
if(typeof get === "function"){
let defaultValue;
try{
defaultValue = get.call(instanceObj);//获取属性值 Object.getOwnPropertyDescriptor(window,'name').get.call(window)
}catch(e){
}
if(defaultValue == undefined || defaultValue instanceof Object){
code += `get:function(){return ldvm.toolsFunc.dispatch(this,${objName},"${protoName}","${prop}_get",arguments);}, `;
}else{
if(typeof defaultValue === 'string'){
code += `get:function(){return ldvm.toolsFunc.dispatch(this,${objName},"${protoName}","${prop}_get",arguments,'${defaultValue}');}, `;
}else if(typeof value === "symbol"){
code += `get:function(){return ldvm.toolsFunc.dispatch(this,${objName},"${protoName}","${prop}_get",arguments,${defaultValue.toString()});}, `;
}else{
code += `get:function(){return ldvm.toolsFunc.dispatch(this,${objName},"${protoName}","${prop}_get",arguments,${defaultValue});}, `;
}
}
}else{
code += `get:undefined, `;
}
}
if(descriptor.hasOwnProperty("set")){//没有默认值
let set = descriptor.set;
if(typeof set === "function"){
code += `set:function(){return ldvm.toolsFunc.dispatch(this,${objName},"${protoName}","${prop}_set",arguments);}`;
}else{
code += `set:undefined`;
}
}
code += "}";
return code;
}
//getProtoEnvCode(Window);
//getObjEnvCode(window,"window")
补充代码
//定义对象属性defineProperty
ldvm.toolsFunc.defineProperty = function defineProperty(obj,prop,oldDescriptor){
let newDescriptor = {};//新的构造器
newDescriptor.configurable = ldvm.config.proxy || oldDescriptor.configurable;//如果开启代理必须是true,如果对象的configurable是false,不能被proxy代理
newDescriptor.enumerable = oldDescriptor.enumerable;
if(oldDescriptor.hasOwnProperty("writable")){
newDescriptor.writable = ldvm.config.proxy || oldDescriptor.writable;//如果开启代理必须是true
}
if(oldDescriptor.hasOwnProperty("value")){
let value = oldDescriptor.value;
if(typeof value === "function"){
ldvm.toolsFunc.safeFunc(value,prop);
}
newDescriptor.value = value;
}
if(oldDescriptor.hasOwnProperty("get")){
let get = oldDescriptor.get;
if(typeof get === "function"){
ldvm.toolsFunc.safeFunc(get,`get ${prop}`);
}
newDescriptor.get = get;
}
if(oldDescriptor.hasOwnProperty("set")){
let set = oldDescriptor.set;
if(typeof set === "function"){
ldvm.toolsFunc.safeFunc(set,`set ${prop}`);
}
newDescriptor.set = set;
}
Object.defineProperty(obj,prop,newDescriptor);
}
在补环境时,浏览器对象属性如此之多,每次一个一个手工补是不是很繁琐,这种情况使用自动脱浏览器环境就方便了,可以自动生成补环境代码放到自己项目里,这样就能省去大量人工工作。