代理(Proxy)是一种可以拦截并改变底层JavaScript引擎操作的包装器,在新语言中通过它暴露内部运作的对象,从而让开发者可以创建内建的对象。

数组问题

在ECMAScript6出现之前,开发者不能通过自己定义的对象模仿JavaScript数组对象的行为方式。当给数组的特定元素赋值时,影响到该数组的length属性,也可以通过length属性修改数组元素。

let colors = ["red", "green", "blue"];

console.log(colors.length); // 3

colors[3] = "black";

console.log(colors.length); // 4
console.log(colors[3]); // "black" colors.length = 2; console.log(colors.length); // 2
console.log(colors[3]); // undefined
console.log(colors[2]); // undefined
console.log(colors[1]); // "green"

Note

数值属性和length属性具有这种非标准行为,因而在ECMAScript中数组被认为是奇异对象(exotic object,与普通对象相对)。

代理和反射

调用 new Proxy() 可创建代替其他目标(taget)对象的代理,它虚拟化了目标,所以二者看起来功能一致。

代理可以拦截 JavaScript 引擎内部目标的底层对象操作,这些底层操作被拦截后会触发响应特定操作的陷阱函数。

反射API可以Reflect对象的形式出现,对象中方法的默认特性与相同的底层操作一致,而代理可以覆写这些操作,每个代理陷阱对应一个命名和参数都相同的Reflect方法。

代理陷阱 覆写的特性 默认特性
get 读取一个属性值 Reflect.get()
set 写入一个属性值 Reflect.set()
has in 操作符 Reflect.has()
deleteProperty delete 操作符 Reflect.deleteProperty()
getPrototypeOf Object.getPrototypeOf() Reflect.getPrototypeOf()
setPrototypeOf Object.setPrototypeOf() Reflect.setPrototypeOf()
isExtensible Object.isExtensible() Reflect.isExtensible()
preventExtensions Object.preventExtensions() Reflect.preventExtensions()
getOwnPropertyDescriptor Object.getOwnPropertyDescriptor() Reflect.getOwnPropertyDescriptor()
defineProperty Object.defineProperty() Reflect.defineProperty()
ownKeys Object.keys()、Object.getOwnPropertyNames()和Object.getOwnPropertySymbols() Reflect.ownKeys()
apply 调用一个函数 Reflect.apply()
construct 用new调用一个函数 Reflect.construct()

创建一个简单的代理

Proxy构造函数有两个参数

  • 目标(target)
  • 处理程序(handler)

    处理程序是定义一个或多个陷阱的对象,在代理中,出了专门为操作定义的陷阱外,其余操作均使用默认特性。

    不使用任何陷阱的处理程序等价于简单的转发代理。
let target = {};
let proxy = new Proxy(target, {}); proxy.name = "proxy";
console.log(proxy.name); // "proxy"
console.log(target.name); // "proxy" target.name = "target";
console.log(proxy.name); // "target"
console.log(target.name); // "target"

使用set陷阱验证属性

set陷阱接受4个参数:

  • trapTarget

    用于接收属性(代理的目标)的对象
  • key

    要写入的属性键(字符串或Symbol类型)
  • value

    被写入属性的值
  • receiver

    操作发生的对象(通常是代理)

Reflect.set()是set陷阱对应的反射方法和默认特性,它和set陷阱一样也接受同样的4个参数。

let target = {
name: "target"
}; let proxy = new Proxy(target, {
set(trapTarget, key, value, receiver) {
if (!trapTarget.hasOwnProperty(key)) {
if (isNaN(value)) {
throw new TypeError("属性必须是数字");
}
} return Reflect.set(trapTarget, key, value, receiver);
}
}); proxy.count = 1;
console.log(proxy.count); // 1
console.log(target.count); // 1 proxy.name = "proxy";
console.log(proxy.name); // "proxy"
console.log(target.name); // "proxy" // 抛出错误:
// Uncaught TypeError: 属性必须是数字
proxy.anotherName = "proxy";

用get陷阱验证对象结构(Object Shape)

get陷阱接受3个参数:

  • trapTarget

    被读取属性的源的对象(代理的目标)
  • key

    被读取的属性键
  • value

    操作发生的对象(通常是代理)

Reflect.get()也接受同样3个参数并返回属性的默认值。

let proxy = new Proxy({}, {
get(trapTarget, key, receiver) {
if (!(key in receiver)) {
throw new TypeError("属性" + key + "不存在");
} return Reflect.get(trapTarget, key, receiver);
}
}); proxy.name = "proxy";
console.log(proxy.name); // "proxy" // 抛出错误:
// Uncaught TypeError: 属性nme不存在
console.log(proxy.nme);

使用has陷阱隐藏已有属性

可以用in操作符来检测给定对象中是否含有某个属性,如果自由属性或原型属性匹配的名称或Symbol就返回true。

let target = {
value: 42
}; console.log("value" in target); // true
console.log("toString" in target); // true

在代理中使用has陷阱可以拦截这些in操作并返回一个不同的值。

in陷阱接受2个参数:

  • trapTarget

    读取属性的对象(代理的目标)
  • key

    要检查的属性值(字符串或Symbol)
let target = {
name: "target",
vlaue: 42
}; let proxy = new Proxy(target, {
has (trapTarget, key) {
if (key === "value") {
return false;
} else {
return Reflect.has(trapTarget, key);
}
}
}); console.log("value" in proxy); // false
console.log("name" in proxy); // true
console.log("toString" in proxy); // true

用deleteProperty陷阱防止删除属性

delete操作符可以从对象中删除属性,如果成功则返回true,不成功则返回false。

在严格模式下,如果你尝试删除一个不可配置(nonconfigurable)属性则会导致程序抛出错误,而在非严格模式下只是返回false。

每当通过delete操作符删除对象属性时,deleteProperty陷阱都会被调用,它接受2个参数:

  • trapTarget

    要删除属性的对象(代理的目标)
  • key

    要删除的属性键(字符串或Symbol)

Reflect.deleteProperty()方法为deleteProperty陷阱提供默认实现,并且接受同样的两个参数。

let target = {
name: "target",
value: 42
}; let proxy = new Proxy(target, {
deleteProperty(trapTarget, key) {
if (key === "value") {
return false;
} else {
return Reflect.deleteProperty(trapTarget, key);
}
}
}); console.log("value" in proxy); // true let result1 = delete proxy.value;
console.log(result1); // false console.log("value" in proxy); // true console.log("name" in proxy); // true let result2 = delete proxy.name;
console.log(result2); // true console.log("name" in proxy); // false

原型代理陷阱

ES6中新增的Object.setPrototypeOf()方法,它被用于作为ES5中的Object.getPrototype()方法的补充。通过代理中的setPrototypeOf陷阱和getPrototypeOf陷阱可以拦截这两个方法的执行过程。

setPrototypeOf陷阱接受2个参数:

  • trapTarget

    接受原型设置的对象(代理的目标)
  • proto

    作为原型使用的对象

传入Object.setPrototypeOf()方法和Reflect.setPrototypeOf()方法的均是以上两个参数。

getPrototypeOf陷阱、Object.getPrototypeOf()方法和Reflect.getPrototypeOf()方法只接受参数trapTarget。

原型代理陷阱的运行机制

原型代理陷阱有一些限制:

  1. getPrototypeOf陷阱必须返回对象或null

  2. 在setPrototypeOf陷阱中,如果操作失败则返回的一定是false,此时Object.setPrototypeOf()会抛出错误,如果setPrototypeOf返回了任何不是false的值,那么Object.setPrototypeOf()便假设操作成功。

let target = {};
let proxy = new Proxy(target, {
getPrototypeOf(trapTarget) {
return null;
},
setPrototypeOf(trapTarget, proto) {
return false;
}
}); let targetProto = Object.getPrototypeOf(target);
let proxyProto = Object.getPrototypeOf(proxy); console.log(targetProto === Object.prototype); // true
console.log(proxyProto === Object.prototype); // false
console.log(proxyProto); // null // 成功
Object.setPrototypeOf(target, {}); // 给不存在的属性赋值会抛出错误:
// Uncaught TypeError: 'setPrototypeOf' on proxy: trap returned falsish
Object.setPrototypeOf(proxy, {});

可以使用Reflect上的对应方法实现这两个陷阱的默认行为。

let target = {};
let proxy = new Proxy(target, {
getPrototypeOf(trapTarget) {
return Reflect.getPrototypeOf(trapTarget);
},
setPrototypeOf(trapTarget, proto) {
return Reflect.setPrototypeOf(trapTarget, proto);
}
}); let targetProto = Object.getPrototypeOf(target);
let proxyProto = Object.getPrototypeOf(proxy); console.log(targetProto === Object.prototype); // true
console.log(proxyProto === Object.prototype); // true // 成功
Object.setPrototypeOf(target, {}); // 成功:
Object.setPrototypeOf(proxy, {});

对象可扩展性陷阱

ECMAScript 5 已经通过 Object.preventExtensions() 方法和 Object.isExtensible() 方法修正了对象的可扩展性;

ECMAScript 6 可以通过代理中的 preventExtensions 和 isExtensible 陷阱拦截这两个方法并调用底层对象。

两个陷阱都接受唯一参数 trapTarget 对象,并调用它上面的方法。

isExtensible 陷阱返回的一定是一个 boolean 值,表示对象是否可扩展;

preventExtensions 陷阱返回的也一定是布尔值,表示操作是否成功。

Reflect.preventExtensions() 方法和 Reflect.isExtensible() 方法实现了相应陷阱中的默认行为,二两都返回布尔值。

两个基础示例

默认实现:

let target = {};
let proxy = new Proxy(target, {
isExtensible(trapTarget) {
return Reflect.isExtensible(trapTarget);
},
preventExtensions(trapTarget) {
return Reflect.preventExtensions(trapTarget);
}
}); console.log(Object.isExtensible(target)); // true
console.log(Object.isExtensible(proxy)); // true Object.preventExtensions(proxy); console.log(Object.isExtensible(target)); // false
console.log(Object.isExtensible(proxy)); // false

使用陷阱使 Object.preventExtensions() 对 proxy 失效。

let target = {};
let proxy = new Proxy(target, {
isExtensible(trapTarget) {
return Reflect.isExtensible(trapTarget);
},
preventExtensions(trapTarget) {
return false;
}
}); console.log(Object.isExtensible(target)); // true
console.log(Object.isExtensible(proxy)); // true // 抛出错误:
// Uncaught TypeError: 'preventExtensions' on proxy: trap returned falsish
Object.preventExtensions(proxy); console.log(Object.isExtensible(target)); // true
console.log(Object.isExtensible(proxy)); // true

属性描述符陷阱

ECMAScript 5 最重要的特性之一是可以使用 Object.defineProperty() 方法定义属性特性(property attribute)。可以通过 Object.getOwnPropertyDescriptor() 方法来获取这些属性。

在代理中可以分别用 defineProperty 陷阱和 getOwnPropertyDescriptor 陷阱拦截 Object.defineProperty() 方法和 Object.getOwnPropertyDescriptor() 方法的调用。

defineProperty 陷阱接受以下参数:

  • trapTarget

    要定义属性的对象(代理的目标)
  • key

    属性的键(字符串或Symbol)
  • descriptor

    属性的描述符对象

操作成功后返回 true,否则返回 false。

getOwnPropertyDescriptor 陷阱接受以下参数:

  • trapTarget

    要定义属性的对象(代理的目标)
  • key

    属性的键(字符串或Symbol)

最终返回描述符。

陷阱默认行为示例:

let proxy = new Proxy({}, {
defineProperty(trapTarget, key, descriptor) {
return Reflect.defineProperty(trapTarget, key, descriptor);
},
getOwnPropertyDescriptor(trapTarget, key) {
return Reflect.getOwnPropertyDescriptor(trapTarget, key);
}
}); Object.defineProperty(proxy, "name", {
value: "proxy"
}); console.log(proxy.name); // "proxy" let descriptor = Object.getOwnPropertyDescriptor(proxy, "name"); console.log(descriptor.value); // "proxy"

给 Object.defineProperty() 添加限制

defineProperty 陷阱返回布尔值来表示操作是否成功。

返回 true 时,Object.defineProperty() 方法成功执行;

返回 false 时, Object.defineProperty() 方法抛出错误。

例:阻止 Symbol 类型的属性

let proxy = new Proxy({}, {
defineProperty(trapTarget, key, descriptor) {
if (typeof key === "symbol") {
return false;
} return Reflect.defineProperty(trapTarget, key, descriptor);
}
}); Object.defineProperty(proxy, "name", {
value: "proxy"
}); console.log(proxy.name); // "proxy" let nameSymbol = Symbol("name"); // 抛出错误:
// Uncaught TypeError: 'defineProperty' on proxy: trap returned falsish for property 'Symbol(name)'
Object.defineProperty(proxy, nameSymbol, {
value: "proxy"
});

描述符对象限制

defineProperty 陷阱

defineProperty 陷阱的描述对象已规范化,只有下列属性会被传递给 defineProperty 陷阱的描述符对象。

  • enumerable
  • configurable
  • value
  • writable
  • get
  • set
let proxy = new Proxy({}, {
defineProperty(trapTarget, key, descriptor) {
console.log(descriptor.value); // "proxy"
console.log(descriptor.name); // undefined return Reflect.defineProperty(trapTarget, key, descriptor);
}
}); Object.defineProperty(proxy, "name", {
value: "proxy",
name: "custom"
});

getOwnPropertyDescriptor 陷阱

getOwnPropertyDescriptor 陷阱的返回值必须是 null、undefined或一个对象;

如果返回对象,则对象自己的属性只能是 enumerable、configurable、vlaue、writable、get和set;

在返回的对象中使用不被允许的属性会抛出一个错误。

let proxy = new Proxy({}, {
getOwnPropertyDescriptor(trapTarget, key) {
return {
name: "proxy"
};
}
}); // 给不存在的属性赋值会抛出错误
// Uncaught TypeError: 'getOwnPropertyDescriptor' on proxy: trap reported non-configurability for property 'name' which is either non-existant or configurable in the proxy target
let descriptor = Object.getOwnPropertyDescriptor(proxy, "name");

这条限制可以确保无论代理中使用了什么方法,Object.getOwnPropertyDescriptor() 返回值的结构总是可靠的。

ownKeys 陷阱

ownKeys 陷阱可以拦截内部方法 [[OwnPropertyKeys]],通过返回一个数组的值可以覆写其行为。

这个数组被用于 Object.keys()、Object.getOwnPropertyNames()、Object.getOwnPropertySymbols() 和 Object.assign() 4个方法,Object.assign() 方法用数组来确定需要复制的属性。

ownKeys 陷阱通过 Reflect.ownKeys() 方法实现默认的行为,返回的数组中包含所有自有属性的键名,字符串类型和 Symbol 类型的都包含在内。

Object.getOwnPropertyNames() 方法和 Object.keys() 方法返回的结果将 Symbol 类型的属性名排除在外;

Object.getOwnPropertySymbols() 方法返回的结果将字符串类型的属性名排除在外;

Object.assign() 方法支持字符串和 Symbol 两种类型。

ownKeys 陷阱唯一接受的参数时操作的目标,返回值必须是一个数组或类数组对象,否则就抛出错误。

例:过滤任何以下划线字符开头的属性名称。

let proxy = new Proxy({}, {
ownKeys(trapTarget) {
return Reflect.ownKeys(trapTarget).filter(key => {
return typeof key !== "string" || key[0] !== "_";
});
}
}); let nameSymbol = Symbol("name"); proxy.name = "proxy";
proxy._name = "private";
proxy[nameSymbol] = "symbol"; let names = Object.getOwnPropertyNames(proxy),
keys = Object.keys(proxy),
symbols = Object.getOwnPropertySymbols(proxy); console.log(names.length); // 1
console.log(names[0]); // "name" console.log(keys.length); // 1
console.log(keys[0]); // "name" console.log(symbols.length); // 1
console.log(symbols[0]); // "Symbol(name)"

函数代理的 apply 和 construct 陷阱

所有代理陷阱中,只有 apply 和 construct 的代理目标是一个函数。

函数有两个内部方法 [[Call]] 和 [[Construct]],apply 陷阱和 construct 陷阱可以覆写这些内部方法。

若使用 new 操作符调用函数,则执行 [[Construct]] 方法;若不用,则执行 [[Call]] 方法。

apply 陷阱和 Reflect.apply() 都接受以下参数:

  • trapTarget

    被执行的函数(代理的目标)
  • thisArg

    函数被调用时内部this的值
  • argumentList

    传递给函数的参数数组

当使用 new 调用函数时调用的 construct 陷阱接受以下参数:

  • trapTarget

    被执行的函数(代理的目标)
  • argumentList

    传递给函数的参数数组

Reflect.construct() 方法也接受这两个参数,其还有一个可选的第三个参数 newTarget。

let target = function() { return 42; },
proxy = new Proxy(target, {
apply: function(trapTarget, thisArg, argumentList) {
return Reflect.apply(trapTarget, thisArg, argumentList);
},
construct: function(trapTarget, argumentList) {
return Reflect.construct(trapTarget, argumentList);
}
}); // 一个目标是函数的代理开起来也像一个函数
console.log(typeof proxy); // function
console.log(proxy()); // 42
var instance = new proxy();
console.log(instance instanceof proxy); // true
console.log(instance instanceof target); // true

验证函数参数

例:验证所有参数必须是数字:

// 将所有参数相加
function sum(...values) {
return values.reduce((previous, current) => previous + current, 0);
} let sumProxy = new Proxy(sum, {
apply: function(trapTarget, thisArg, argumentList) {
argumentList.forEach((arg) => {
if (typeof arg !== "number") {
throw new TypeError("所有参数必须是数字");
}
}); return Reflect.apply(trapTarget, thisArg, argumentList);
},
construct: function(trapTarget, argumentList) {
throw new TypeError("该函数不可通过new来调用");
}
}); console.log(sumProxy(1, 2, 3, 4)); // 10 // 抛出错误
// Uncaught TypeError: 所有参数必须是数字
console.log(sumProxy(1, "2", 3, 4)); // 抛出错误
// Uncaught TypeError: 该函数不可通过new来调用
let result = new sumProxy();

可调用的类构造函数

使用 apply 陷阱创建实例

class Person {
constructor(name) {
this.name = name;
}
} let PersonProxy = new Proxy(Person, {
apply: function(trapTarget, thisArg, argumentList) {
return new trapTarget(...argumentList);
}
}); let me = PersonProxy("JiaJia");
console.log(me.name); // JiaJia
console.log(me instanceof Person); // true
console.log(me instanceof PersonProxy); // true

可撤销代理

可以使用 Proxy.revocable() 方法创建可撤销的代理,该方法采用与 Proxy 构造函数相同的参数:目标对象和代理处理程序。

返回值是具有以下属性的对象:

  • proxy

    可被撤销的代理对象
  • revoke

    撤销代理要调用的函数
let target = {
name: "target"
}; let { proxy, revoke } = Proxy.revocable(target, {}); console.log(proxy.name); // target revoke(); // 抛出错误
// Uncaught TypeError: Cannot perform 'get' on a proxy that has been revoked
console.log(proxy.name);

解决数组问题

数组问题

let colors = ["red", "green", "blue"];

console.log(colors.length); // 3

colors[3] = "black";

console.log(colors.length); // 4
console.log(colors[3]); // black colors.length = 2;

自定义数组类型

function toUint32(value) {
return Math.floor(Math.abs(Number(value))) % Math.pow(2, 32);
} function isArrayIndex(key) {
let numericKey = toUint32(key);
return String(numericKey) == key && numericKey < (Math.pow(2, 32) - 1);
} class MyArray {
constructor(length = 0) {
this.length = length;
return new Proxy(this, {
set(trapTarget, key, value) {
let currentLength = Reflect.get(trapTarget, "length"); if (isArrayIndex(key)) {
let numericKey = Number(key);
if (numericKey >= currentLength) {
Reflect.set(trapTarget, "length", numericKey + 1);
}
} else if (key === "length") {
if (value < currentLength) {
for (let index = currentLength - 1; index >= value; index--) {
Reflect.deleteProperty(trapTarget, index);
}
}
} return Reflect.set(trapTarget, key, value);
}
});
}
} let colors = new MyArray(3);
console.log(colors instanceof MyArray); // true
console.log(colors.length); // 3 let colors2 = new MyArray(5);
console.log(colors.length); // 3
console.log(colors2.length); // 5 colors[0] = "red";
colors[1] = "green";
colors[2] = "blue";
colors[3] = "black"; console.log(colors.length); // 4 colors.length = 2;
console.log(colors.length); // 2
console.log(colors[3]); // undefined
console.log(colors[2]); // undefined
console.log(colors[1]); // "green"
console.log(colors[0]); // "red"

将代理作为原型

let target = {};
let proxy = new Proxy(target, {
defineProperty(trapTarget, name, descriptor) {
return false;
}
});
let newTarget = Object.create(proxy); Object.defineProperty(newTarget, "name", {
value: "newTarget"
}); console.log(newTarget.name); // "newTarget"
console.log(newTarget.hasOwnProperty("name")); // true
console.log(Object.getPrototypeOf(newTarget) === proxy); // true

关于 Object.create() 方法可以参照 这里

上例中 newTarget 的原型是代理,但是在对象上定义属性的操作不需要操作对象原型,所以没有触发代理中的陷阱。

尽管代理作为原型使用时及其受限,但有几个陷阱仍然有用。

在原型上使用 get 陷阱

let target = {};
let thing = Object.create(new Proxy(target, {
get(trapTarget, key, value) {
throw new ReferenceError(`${key} deesn't exist`);
}
})); thing.name = "thing";
console.log(thing.name); // "thing" // 抛出异常:
// Uncaught ReferenceError: unknown deesn't exist
let unknown = thing.unknown;

访问对象上不存在的属性时,会触发原型中的 get 陷阱。

在原型上使用 set 陷阱

let target = {};
let thing = Object.create(new Proxy(target, {
set (trapTarget, key, value, receiver) {
return Reflect.set(trapTarget, key, value, receiver);
}
})); console.log(thing.hasOwnProperty("name")); // false // 触发set陷阱
thing.name = "thing";
console.log(thing.name); // "thing"
console.log(thing.hasOwnProperty("name")); // true // 不触发set陷阱
thing.name = "boo";
console.log(thing.name); // "boo"

在原型上使用 has 陷阱

let target = {}
let thing = Object.create(new Proxy(target, {
has (trapTarget, key) {
return Reflect.has(trapTarget, key);
}
})); // 触发 has 陷阱
console.log("name" in thing); // false
thing.name = "thing";
// 不触发 has 陷阱
console.log("name" in thing); // true

第一次 in 操作符触发 has 陷阱,是因为 name 不是 thing 的自有属性。

将代理用作类的原型

function NoSuchProperty() {

}

let proxy = new Proxy({}, {
get (trapTarget, key, receiver) {
throw new ReferenceError(`${key} doesn't exist`);
}
}); NoSuchProperty.prototype = proxy; class Square extends NoSuchProperty {
constructor(length, width) {
super();
this.length = length;
this.width = width;
}
} let shape = new Square(2, 6); let shapeProto = Object.getPrototypeOf(shape);
console.log(shapeProto === proxy); // false let secondLevelProto = Object.getPrototypeOf(shapeProto);
console.log(secondLevelProto === proxy); // true let area1 = shape.length * shape.width;
console.log(area1); // 12 // 由于 wdth 不存在,抛出错误:
// Uncaught ReferenceError: wdth doesn't exist
let area2 = shape.length * shape.wdth;

【读书笔记】【深入理解ES6】#12-代理(Proxy)和反射(Reflection)API的更多相关文章

  1. 代理(Proxy)和反射(Reflection)

    前面的话 ES5和ES6致力于为开发者提供JS已有却不可调用的功能.例如在ES5出现以前,JS环境中的对象包含许多不可枚举和不可写的属性,但开发者不能定义自己的不可枚举或不可写属性,于是ES5引入了O ...

  2. 20150206读书笔记<深入理解计算机系统>

    ●第一章 C是系统级编程的首选.C++显示支持抽象,属于应用级程序设计语言. 简单例子: 一个典型系统的硬件组成: 存储器的层次结构: 注:存储器层次结构的设计思想是,该层存储器作为下一层存储器的高速 ...

  3. 深入理解ES6之——代理和反射(proxy)

    通过调用new proxy()你可以创建一个代理来替代另一个对象(被称为目标),这个代理对目标对象进行了虚拟,因此该代理与该目标对象表面上可以被当做同一个对象来对待. 创建一个简单的代理 当你使用Pr ...

  4. CSharp设计模式读书笔记(13):代理模式(学习难度:★★★☆☆,使用频率:★★★★☆)

    代理模式:给某一个对象提供一个代理或占位符,并由代理对象来控制对原对象的访问. 模式角色与结构: 示例代码: using System; using System.Collections.Generi ...

  5. python 进阶读书笔记1 -- 理解python一切皆对象

    理解python一切皆对象: 1.所有的类都是由type创建的 2.所有的类的基类都是object 3.type是类,也是实例,type的基类是object,type对象是由type创建的 4.obj ...

  6. 【读书笔记::深入理解linux内核】内存寻址【转】

    转自:http://www.cnblogs.com/likeyiyy/p/3837272.html 我对linux高端内存的错误理解都是从这篇文章得来的,这篇文章里讲的 物理地址 = 逻辑地址 – 0 ...

  7. 【读书笔记::深入理解linux内核】内存寻址

    我对linux高端内存的错误理解都是从这篇文章得来的,这篇文章里讲的 物理地址 = 逻辑地址 – 0xC0000000:这是内核地址空间的地址转换关系. 这句话瞬间让我惊呆了,根据我的CPU的知识,开 ...

  8. 20150207读书笔记<深入理解计算机系统2-1>

    第二章 信息存储 (1)  多数计算机以一个字节作为最小可寻址的存储器单元. 机器级程序将存储器看成一个非常大的字节数组,称为虚拟存储器. 存储器的每个字节都由唯一的数字标识,称为它的地址. 所有可能 ...

  9. 读书笔记 effective c++ Item 12 拷贝对象的所有部分

    1.默认构造函数介绍 在设计良好的面向对象系统中,会将对象的内部进行封装,只有两个函数可以拷贝对象:这两个函数分别叫做拷贝构造函数和拷贝赋值运算符.我们把这两个函数统一叫做拷贝函数.从Item5中,我 ...

  10. 《Linux命令行与shell脚本编程大全》- 读书笔记3 - 理解shell

    当用户登录终端的时候,通常会启动一个默认的交互式shell.系统究竟启动哪个shell,这取决于用户配置.一般这个shell都是/bin/shell.默认的系统shell(/bin/sh)用于系统sh ...

随机推荐

  1. iOS 从应用程序跳转到评价界面

    1,跳转到App Store: NSString *str = [NSString stringWithFormat:@"http://itunes.apple.com/us/app/id% ...

  2. Linux基础:文件查找find

    写在前面 在linux的日常管理中,find的使用频率很高,熟练掌握对提高工作效率很有帮助. find的语法比较简单,常用参数的就那么几个,比如-name.-type.-ctime等.初学的同学直接看 ...

  3. Docker 搭建 etcd 集群

    阅读目录: 主机安装 集群搭建 API 操作 API 说明和 etcdctl 命令说明 etcd 是 CoreOS 团队发起的一个开源项目(Go 语言,其实很多这类项目都是 Go 语言实现的,只能说很 ...

  4. Linux CentOS完全卸载PHP

    很无语,CentOS居然php版本才5.1.6,很多开源的CMS无法安装. 查看php版本命令: #php -v 下面的命令是删除不干净的 #yum remove php 因为使用这个命令以后再用 # ...

  5. python self

    Python要self的理由 Python的类的方法和普通的函数有一个很明显的区别,在类的方法必须有个额外的第一个参数(self),但在调用这个方法的时候不必为这个参数赋值(显胜于隐的引发). Pyt ...

  6. [原创]mysql的zip包如何在windows下安装

    今天在尝试zipkin的链路数据写入mysql,本机恰好没有按照mysql.找到一个很久前谁发的mysql-5.6.19-winx64.zip,版本不新?别挑剔啦,只是本机测试,能用就好哈哈.. 解压 ...

  7. .Net版InfluxDB客户端使用时的一些坑

    1.如果应用程序是WebAPi,则需要使用同步版的InfluDB客户端 2.如果应用程序是Winform或Console程序或Windows服务,则使用同步或异步版客户端都可以,建议用异步版 3.如果 ...

  8. 【HTML】HTML基础知识

    <!DOCTYPE html>表示HTML5文档申明,不区别大小写,通常这么写. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 ...

  9. Solr集群搭建详细教程(二)

    注:欢迎大家转载,非商业用途请在醒目位置注明本文链接和作者名dijia478,商业用途请联系本人dijia478@163.com. 之前步骤:Solr集群搭建详细教程(一) 三.solr集群搭建 注意 ...

  10. Hibernate框架HQL语句

    这篇随笔将会记录hql的常用的查询语句,为日后查看提供便利. 在这里通过定义了三个类,Special.Classroom.Student来做测试,Special与Classroom是一对多,Class ...