导航
不要因为 Vue 使用到了 Object.defineProperty()
数据劫持,就把它和 Proxy 混为一谈。它俩不是一个东西
Object.defineProperty(obj, prop, descriptor)
是直接处理 obj,然后当操作 obj 时,会在 set、get 方法中进行拦截
自定义对象属性的获取、赋值、枚举、函数调用等功能
let target = {
a: 1,
b: 2
}
let proxy = new Proxy(target, {
get(target, prop) {
console.log('This is property value ' + target[prop]);
return target[prop];
},
set(target, prop, value) {
target[prop] = value;
}
});
console.log("proxy.a", proxy.a); // 走了代理 This is ...
console.log("target.a", target.a); // 直接访问,没走代理。没显示 This is ...
proxy.b = 3;
console.log("target.b", target.b); // 3
console.log("proxy.b", proxy.b); // 3
console.log(proxy); // Proxy {a: 1, b: 2}
let arr = [
{ name: 'Lance', age: 27 },
{ name: 'GC', age: 31 },
{ name: 'Jerry', age: 29 },
{ name: 'Sherry', age: 30 }
];
let persons = new Proxy(arr, {
get(arr, prop) {
return arr[prop];
},
set(arr, prop, value) {
arr[prop] = value;
}
});
persons[0] = { name: 'Xi', age: 30 }
console.log(arr, persons);
// [
// { name: 'Xi', age: 30 },
// { name: 'GC', age: 31 },
// { name: 'Jerry', age: 29 },
// { name: 'Sherry', age: 30 }
// ] [
// { name: 'Xi', age: 30 },
// { name: 'GC', age: 31 },
// { name: 'Jerry', age: 29 },
// { name: 'Sherry', age: 30 }
// ]
let fn = function() {
console.log('I am a function. ');
}
fn.a = 123;
let newFn = new Proxy(fn, {
get(fn, prop) {
return fn[prop] + ' This is a Proxy return';
}
});
console.log(newFn.a); // 123 This is a Proxy return
let target = {
a: 1,
b: 2
}
let proxy = new Proxy(target, {
get(target, prop) {
return 'GET: ' + prop + ' = ' + target[prop];
},
set(target, prop, value) {
target[prop] = value;
console.log('SET: ' + prop + ' = ' + value);
},
has(target, prop) {
console.log(target[prop]);
}
});
console.log('a' in proxy); // false
console.log(proxy); // a, b 在 Proxy 的 Target 下
let target = {
a: 1,
b: 2
}
let proxy = new Proxy(target, {
get(target, prop) {
return 'GET: ' + prop + ' = ' + target[prop];
},
set(target, prop, value) {
target[prop] = value;
console.log('SET: ' + prop + ' = ' + value);
},
has(target, prop) {
return Reflect.has(target, prop);
},
deleteProperty(target, prop) {
delete target[prop];
console.log(1);
}
});
delete proxy.b;
console.log("proxy", proxy);
console.log("target", target);
var obj = { a: 1, b: 2 };
var proto = Object.getPrototypeOf(obj);
console.log(proto); // Object.prototype
console.log(obj.__proto__);
console.log(Object.prototype);
var obj = { a: 1, b: 2 };
Object.setPrototypeOf(obj, { c: 3, d: 4 });
// obj.__proto__ = { c: 3, d: 4};
// Object.prototype = { c: 3, d: 4 };
console.log(obj);
Object.isExtensible() 方法判断一个对象是否是可扩展的(是否可以在它上面添加新的属性)。
var extensible = Object.isExtensible(obj);
console.log(extensible); // true
Object.freeze(obj); // 冻结
var extensible2 = Object.isExtensible(obj);
console.log(extensible2); // false
var obj = { a: 1, b: 2 };
Object.seal(obj); // 封闭对象
obj.c = 3; // 不可新增
console.log(obj);
delete obj.a; // 不可删除
console.log(obj);
obj.b = 3; // 可修改原有属性
console.log(obj);
for (const key in obj) {
console.log(`key: ${key} - val: ${obj[key]}`);
}
var obj = { a: 1, b: 2 };
Object.freeze(obj); // 冻结对象
obj.c = 3; // 不可新增
console.log(obj);
delete obj.a; // 不可删除
console.log(obj);
obj.b = 3; // 不可修改
console.log(obj);
for (const key in obj) {
console.log(`key: ${key} - val: ${obj[key]}`);
}
var obj = { a: 1, b: 2 };
Object.setPrototypeOf(obj, { c: 3, d: 4 });
console.log(Object.getOwnPropertyNames(obj)); // ['a', 'b']
var obj = { a: 1, b: 2 };
Object.preventExtensions(obj);
obj.c = 3;
console.log(obj);
delete obj.a;
console.log(obj);
var obj = { a: 1, b: 2 };
console.log(obj.hasOwnProperty('a'));
var obj = { a: 1, b: 2 };
console.log('c' in obj);
console.log('a' in obj);
console.log(obj.a);
var obj = { a: 1, b: 2 };
obj.a = 3;
obj['b'] = 4;
console.log(obj);
var obj = { a: 1, b: 2 };
delete obj.a;
console.log(obj);
var obj = { a: 1, b: 2 };
for (var k in obj) {
console.log(obj[k]);
}
var obj = { a: 1, b: 2 };
console.log(Object.keys(obj));
function test() {}
test();
test.call/apply
var obj = { a: 1, b: 2 };
obj.test = function() {};
obj.test();
function Test() {}
new Test();
function MyProxy(target, handler) {
const _target = deepClone(target);
Object.keys(_target).forEach(key => {
Object.defineProperty(_target, key, {
get() {
return handler.get && handler.get(target, key);
},
set(newVal) {
handler.set && handler.set(target, key, newVal);
}
})
});
return _target;
function deepClone(org, tar) {
let target = tar || {},
toStr = Object.prototype.toString,
arrType = '[object Array]';
for (var key in org) {
if (org.hasOwnProperty(key)) {
let value = org[key];
if (typeof value === 'object' && value !== null) {
if (toStr.call(value) === arrType) {
target[key] = [];
} else {
target[key] = {};
}
deepClone(value, target[key]);
} else {
target[key] = value;
}
}
}
return target;
}
}
const obj = { a: 1, b: 2 }
const proxy = new MyProxy(obj, {
get(obj, prop) {
console.log('GET: ' + prop + ' = ' + obj[prop]);
return obj[prop];
},
set(obj, prop, newVal) {
console.log('SET: ' + prop + ' = ' + newVal);
obj[prop] = newVal;
}
});
proxy.a = 3;
console.log(proxy);
都能对数据进行“拦截”
本质不同
Vue 对 push、pop 等数组方法进行了重写
ES6 中定义的一个内置对象,是方法集合的容器。全局下的一个对象,不能 new
上面讲的14种方法,这里边有13种,少了一个枚举
放在这上面的原因是:
因为很多对象方法,以前都放在 Object 上在,但很多方法不是直接操作 Object,有可能是操作函数、或数组。
由于这样的不合理,所以专门用 Reflect 这样一个容器来装这些方法
使用 Reflect 更合理,因为是用方法返回值
let target = {
a: 1,
b: 2
}
let proxy = new Proxy(target, {
get(target, prop) {
// return target[prop];
return Reflect.get(target, prop);
},
set(target, prop, value) {
const isOk = Reflect.set(target, prop, value);
if (isOk) {
console.log('SET successfully');
}
}
});
proxy.a = 233;
console.log(proxy.b);
console.log(target.a);