对象、类与面向对象编程

对象

一组属性的无序集合

属性

  • 类型

    • 数据属性 value、writable
    • 访问器属性 getter、setter至少有一
  • 定义

    • .操作符:默认可配置、可枚举、可写(数据属性)
    • Object.defineProperty/defineProperties:默认不可配置、不可枚举、只读

    configurable:false。不可删除、不可逆。无法修改其他特性的值(除writable从true改为false)

    读取特性:Object.getOwnPropertyDescriptor / Object.getOwnPropertyDescriptors(ES8)

    属性名有后缀下划线:通常表示该属性不希望在对象方法的外部被访问

合并对象

Object.assign 复制源对象的可枚举且自有的属性到目标对象

  1. 目标只有getter 源对象无法将同名属性复制到目标对象=>报错
  2. 目标有setter,源对象通过执行[[Get]]获取同名属性值,给到目标对象的[[Setter]]

中途抛错=>完成部分复制

新增的定义和操作对象的语法糖

  1. 属性简写(变量名和属性名同名)
  2. 可计算属性:以字面量形式定义 计算失败=>定义失败
  3. 简写方法名:省略function关键字(默认匿名)

对象解构

let {name, age} = person; // 常见
let {name, job='Software Engineer'} = person; // 未获取到时的默认值
let {name: personName, age: personAge} = person; // 内部声明
({name: personName, age: personAge} = person); // 对外部声明的赋值
  1. 嵌套解构

    嵌套的属性,属性值是对象类型或子类型

  2. 部分解构

    过程出错,完成部分赋值

  3. 函数参数以解构形式

    function foo(f1, {name, age}, f2) {}

    第二个参数存在名为name和age的属性

对象创建

封装、避免冗余

  1. 工厂模式

    工厂函数:接收(特定)参数,拼装对象,返回对象

  2. 构造函数模式(声明或表达式都可)

    函数:接收特定参数,拼装this,可无显式返回(默认为this指向的新对象)

    构造调用:1)创建对象;2)连接对象[[prototype]]到函数的prototype对象;3)对象赋值给this;4)执行函数中的代码;5)返回指定对象或默认this。

    可通过instanceof确定引用类型

    问题:定义的对象如果存在类型为function的功能相同的属性,多次调用会产生多个function实例。

  3. 原型模式

    利用函数的prototype属性(包含了它的实例可共享的属性和方法)。

    原型:函数声明后会自动获取prototype属性,默认有一个键为constructor,值指回函数。

    instanceof实际是查函数的prototype对象。

    • xxx.isPrototypeOf(obj):obj的原型链上是不是存在一个xxx指向的对象
    • Object.getPrototypeOf(obj):可用来获取一个对象的原型链
    • Object.setPrototypeOf(obj, proObj):重写一个对象(obj)的原型继承关系——>可能影响性能,也可能影响访问了原[[prototype]]对象的代码

    Object.create:创建对象,并指定原型。

    原型层级遮蔽。

    查属性:

    1. hasOwnProperty:自身属性

    2. in和for-in:查链、可枚举

    3. Object.keys():不查链、可枚举

    4. Object.getOwnPropertyNames():不论是否可枚举,非符号键

      Object.getOwnPropertySymbols():不论是否可枚举,符号键

    枚举顺序:

    1. for-in / Object.keys() 取决于浏览器
    2. getOPN、getOPS、Object.assign:升序枚举数值键、插入顺序枚举字符串和符号键
  4. 对象迭代

    Object.values():值数组

    Object.entreis():键/值对数组

    以上两个方法符号键都会忽略。

    可通过原型封装功能=>重写.prototype属性=>会丢失constructor(可以手动补)

    修改原型对象的两种方式:

    1)整个重写,重新定义一个对象并赋值给.prototype

    2)增/改原型对象属性/值

    js原生引用类型的实现基于原型模式。如需修改原生引用类型的原型对象=>更推荐的做法:创建一个类继承原生类型;直接修改可能导致命名冲突、意外重写。

    原型存在的问题。共享属性中含有引用类型的数据成员(非函数)

继承

  1. 原型链

    实例和原型对象之间构造了引用连接关系

    ①默认原型:Object.prototype

    ②原型与继承:

    ​ instanceof 实例的原型链上出现过构造函数.prototype关联的对象

    ​ isPrototypeOf 判断两个对象之间的关系

    ③方法覆盖(子类覆盖父类):

    ​ 子类.prototype = 父类new出来的实例

    ​ 再修改单个属性(子类.prototype)

    存在的问题:子类实例化时不能给父类构造函数传参

  2. 盗用构造函数:伪多态,没有原型链

    在子类构造函数中通过call或apply调用父类函数(非构造调用)

    ①解决原型链的问题:可传参给父类函数

    问题:

    ​ a. 无链,子类产生的实例无法对父类及其原型对象应用instanceof和isPrototypeOf方法

    ​ b. 必须在构造函数中定义方法(属于实例的方法),函数不能重用(与构造函数模式一样的问题)

  3. 组合继承:伪多态+原型

    ①在子类构造函数中通过call或apply调用父类函数

    ②重写子类原型对象(用new父类产生的实例赋值)

    解决的问题:instanceof、isPrototypeOf 可用;可添加/修改原型方法

  4. 原型式继承:直接关联两个对象

    类似直接使用Object.create

    适合不需要构造函数的场合

  5. 寄生式继承:类似工厂

    类似工厂函数,但不是用裸的Object,以某种方式取得对象(如new等返回新对象的函数),对此对象加属性或方法以增强功能,并返回对象。

    function createAnother(original) {
    let clone = Object.create(original);
    clone.xx = xxx;
    return clone;
    }

    同样适合主要关注对象,而不在乎类型和构造函数的场景。

    存在的问题:必须在构造函数中定义方法(属于实例的方法),函数不能重用(与构造函数模式一样的问题)

  6. 寄生式组合继承:伪多态+Object.create替代new父类(优化3)

    用Object.create()替换new父类实例来重写子类的原型对象(优化3,舍去new中其他多余操作)

    function inheritatePrototype(subT, superT) {
    let proto = Object.create(superT.prototype);
    proto.constructor = subT;
    subT.prototype = proto;
    }
/*
* 属性
*/
let o = {
b: 'test B'
};
// Object.defineProperty(o, "name", {
// value: 0,
// get: function() {
// return 1;
// },
// set: function(val) {
// this.name = val;
// },
// writable: true
// });
// console.log( Object.getOwnPropertyDescriptor(o, "name") );
// TypeError: Invalid property descriptor. Cannot both specify accessors and a value or writable attribute Object.defineProperty(o, "name", {
get: function() {
return this.b;
},
set: function(val) {
this.name = val;
}
});
console.log( Object.getOwnPropertyDescriptor(o, "name") );
// {
// get: [Function: get],
// set: [Function: set],
// enumerable: false,
// configurable: false
// }
console.log( Object.getOwnPropertyDescriptor(o, "name").value ); // undefined
console.log( Object.getOwnPropertyDescriptor(o, "b") );
// {
// value: 'test B',
// writable: true,
// enumerable: true,
// configurable: true
// }
console.log( Object.getOwnPropertyDescriptors(o) );
// {
// b: {
// value: 'test B',
// writable: true,
// enumerable: true,
// configurable: true
// },
// name: {
// get: [Function: get],
// set: [Function: set],
// enumerable: false,
// configurable: false
// }
// } /*
* 合并对象
*/
let dest, src, result;
// 1.目标对象只有同名的set,混入源对象的同名get
// 会先执行源对象的get获取值,把值传递给目标对象的set并执行。
// 无法通过目标对象获取值(目标对象无get)
dest = {
set a(val) {
console.log( `Invoked dest setter with param ${val}` );
}
};
src = {
get a() {
console.log( 'Invoked src getter' );return 1;
}
};
Object.assign( dest, src );
console.log( dest );
// Invoked src getter
// Invoked dest setter with param undefined
// { a: [Setter] } // 2.目标对象只有同名的get,混入源对象的同名set会报错
// Object.assign( src, dest );
// TypeError: Cannot set property a of #<Object> which has only a getter // 3.目标对象有get和set,混入的源对象只有同名set
// 会先执行源对象的get获取值(undefined),执行目标对象的set
src = {
get a() {
console.log( 'Invoked src getter' );
return 1;
},
set a(val) {
console.log( `Invoked src setter with param ${val}` );
}
};
Object.assign( src, dest ); // Invoked src setter with param undefined
console.log( 'src', src ); // src { a: [Getter/Setter] }
console.log( 'src.a', src.a );
// Invoked src getter
// src.a 1 // 4.目标和源都只有get
dest = {
get a() {
console.log( 'dest' );
}
};
src = {
get a() {
console.log( 'src' );
}
};
// Object.assign( dest, src ); // TypeError: Cannot set property a of #<Object> which has only a getter // 通过setter观察覆盖的过程
dest = {
set id(x) {
console.log( x );
}
};
Object.assign(dest, { id: 1 }, { id: 2 }, { id: 3 });
// 1
// 2
// 3 dest = {};
src = {
a: 'foo',
get b() {
throw new Error();
},
c: 'bar'
};
try{
Object.assign( dest, src );
} catch(e) {}
console.log( dest ); // { a: 'foo' } /*
* 新增的定义和操作对象的语法糖
*/
let nameKey="name";
// let o2 = {
// [nameKey]: "lily",
// [ageKey]: 12
// };
// ReferenceError: ageKey is not defined
let o2;
try{
o2 = {
[nameKey]: "lily",
[ageKey]: 12
};
} catch(e) {}
console.log( o2 ); // undefined
o2 = {
[nameKey]: "lily",
};
console.log( o2 ); // { name: 'lily' } /*
* 对象解构
*/
let person = {
name: 'aa',
age: 27
};
let { name, age } = person;
console.log( name, age ); // aa 27
let { name: nameValue, age: ageValue } = person;
console.log( nameValue, ageValue ); // aa 27
/*
let { job } = person;
// 相当于
// let job;
// job = person.job;
console.log( job ); // undefined
*/
let { job = 'OA' } = person;
// 相当于
// let job;
// job = person.job || 'OA';
console.log( job ) ; let gender;
// { gender } = person; // SyntaxError: Unexpected token '='
({ gender } = person);
console.log( gender ); // undefined let personName, personAge, personBar;
try {
({name: personName, foo: {bar: personBar}, age: personAge} = person);
} catch(e) {}
console.log( personName, personBar, personAge ); // aa undefined undefined function printPerson(foo, {name, age}, bar) {
console.log( arguments );
console.log( name, age );
}
function printPerson2(foo, {name: personName, age: personAge}, bar) {
console.log( arguments );
console.log( personName, personAge );
}
printPerson( "1st", person, '2nd' );
// [Arguments] { '0': '1st', '1': { name: 'aa', age: 27 }, '2': '2nd' }
// aa 27
printPerson2( "1st", person, '2nd' );
// [Arguments] { '0': '1st', '1': { name: 'aa', age: 27 }, '2': '2nd' }
// aa 27 /*
* 对象创建 继承
*/
function Foo() {}
Foo.prototype = {};
let f = new Foo();
console.log( f.contructor === Foo ); // false
console.log( f instanceof Foo ); // true function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName = new Function("console.log(this.name)");
}
let p1 = new Person("kk", 12, "farmer");
p1.sayName(); // kk function Student() {}
Student.prototype = {
name: 'class1',
friends: [1, 2, 3]
};
let s1 = new Student();
let s2 = new Student();
s1.friends = [2, 3, 4];
console.log( s1.friends === s2.friends ); // false
console.log( s1.friends, s2.friends ); // [ 2, 3, 4 ] [ 1, 2, 3 ] let k1 = Symbol('k1'), k2 = Symbol('k2');
let o1 = {
1: 1,
first: 'first',
[k1]: 'k1',
second: 'second',
0: 0
};
o1[k2] = 'k2';
o1[3] = 3;
o1.third = 'third';
console.log( Object.getOwnPropertyNames( o1 ) );
// [ '0', '1', '3', 'first', 'second', 'third' ]
console.log( Object.getOwnPropertySymbols( o1 ) );
// [ Symbol(k1), Symbol(k2) ]
Object.assign( o1, { 2: 2 } );
console.log( Object.getOwnPropertyNames( o1 ) );
// [ '0', '1', '2', '3', 'first', 'second', 'third' ]

  1. 类声明与类表达式

    与函数的区别:

    ①函数声明可提升,类定义不行

    ②函数受函数作用域限制,类受块作用域限制

    ③默认情况下,类块中的代码在严格模式下执行

    ④类定义体中可包含constructor、实例方法、获取函数(get)、设置函数(set)和静态类方法(static关键字)。除了静态类方法,其他都定义在原型对象上。

    类表达式的名称:

    ①可通过类表达式赋值的变量的name属性获取

    ②不能在类表达式作用域外部访问这个标识符

    class 的所有方法(包括静态方法和实例方法)都没有原型对象 prototype,所以也没有[[construct]],不能使用 new 来调用。

  2. constructor 类构造函数

    new调用类时,默认调用constructor函数。constructor函数必须使用new操作符调用。

    关于定义:

    如未定义,默认为空函数体。

    关于返回:

    如返回null、symbol、number、string、boolean,则返回刚创建的对象

    如返回{}或其他非空对象,则返回该对象。

    默认返回刚创建的对象。

    实例.constructor 即 类.prototype.contructor

    类.constructor 即 Function.prototype.constructor(类是函数的实例)

  3. 实例成员、原型成员、类成员

    • 实例成员

      在constructor中操作this,或在其他原型函数中操作this。

    • 原型成员

      在class块中定义的方法为原型方法,不能添加成员数据(原始值或对象)

      获取或设置访问器也支持(get、set)

    • 静态类成员

      适合作实例工厂

    • 其他:

      在类定义外部可通过修改原型对象增加成员数据,但不推荐(在共享目标(原型、类)上添加可变数据成员),如Person.prototype.name

      支持生成器函数。普通对象,包括函数原型对象也支持生成器函数。

  4. 继承

    • 语法 extends关键字

      可继承class或function(向后兼容)等任何拥有[[construct]]和prototype的对象

    • constructor、HomeObject和super()

      内部特性[[HomeObject]]始终指向定义该方法的对象(类)

      constructor:

      1. 不显式定义:new调用时默认会调super(),并传入传给派生类的全部参数

      2. 显式定义:

        必须调super()或者显式返回一个对象

        要使用this必须先调super()

      super语法:

      1. 只能在派生类的constructor和方法中使用
      2. 不能单独引用,必须调构造函数或引用静态方法或原型方法
      3. 调用super()后,将返回的实例赋值给this。如需传参给父类构造函数,需手动
    • "伪"对象基类

      1. 不能直接实例化(使用new.target进行拦截)
      2. 子类必须定义某个方法(在父类构造函数中用this.方法名进行检测)
    • 继承内置类型

      如果有实例方法返回新对象实例,默认情况下,新实例与调用实例方法的实例类型一致,如需修改这个行为,可覆盖Symbol.species访问器。如:

      class ... {
      static get [Symbol.species]() {
      return Array;
      }
      }
    • 类混入

      连缀多个混入元素

      如:Person-(继承)->C->B->A

      方式:

      1. 连缀调用

      2. 写一个辅助函数,把嵌套调用展开

        function mix(BaseClass, ...Mixins) {
        return Mixins.reduce((accumulator, current)=>current(accumulator), BaseClass);
        }

      不推荐使用:

      软件设计原则——复合胜过继承。在代码设计中提供极大灵活性。

/* class定义不能被提升
console.log(A);
// node - ReferenceError: Cannot access 'A' before initialization
// chrome - ReferenceError: A is not defined class A {}
*/ /* 作用域限制不一样
{
function FunctionDeclaration() {}
class ClassDelaration {}
}
console.log( FunctionDeclaration ); // [Function: FunctionDeclaration]
console.log( ClassDelaration ); // ReferenceError: ClassDelaration is not defined
*/ /* 类表达式赋值给变量后,类表达式的名称无法在类表达式作用域外部访问
let Person = class PersonName {
identify() {
console.log( Person.name, PersonName.name );
}
}
let p = new Person();
p.identify(); // PersonName PersonName
console.log( p ); // PersonName {}
console.log( Person.name ); // PersonName
console.log( PersonName ); // ReferenceError: PersonName is not defined
*/ /*
* constructor、实例成员、原型成员、类成员
*/
class Person {
set name(newName) { // name_会添加到实例上,name是在原型对象上
this.name_ = newName;
}
get name() {
return this.name_;
}
static locate() {
console.log( 'class', this );
}
static className() {
console.log( 'Person' );
}
}
let p1 = new Person();
// p1.constructor(); // TypeError: Class constructor Person cannot be invoked without 'new' let p2 = new p1.constructor();
console.log( p2 ); // Person {}
console.log( p2 instanceof Person ); // true
console.log( Person ); // [class Person]
console.log( typeof Person ); // function let p3 = new Person.constructor();
console.log( p3.constructor === Person ); // false
console.log( p3 instanceof Person ); // false
console.log( p3 instanceof Person.constructor ); // true console.log( p1.constructor === Person.constructor ); // false
console.log( p1.constructor ); // [class Person]
console.log( Person.constructor ); // [Function: Function]
console.log( p1.constructor === Person.prototype.constructor ); // true Person.locate(); // class [class Person] let p = new class Foo {
constructor(x) {
console.log( x );
}
}('bar');
console.log( p );
// bar
// Foo {} /*
* 继承
*/
function Job() {} class Engineer extends Job {} let e = new Engineer();
console.log( e instanceof Engineer ); // true
console.log( e instanceof Job ); // true class Vehicle {
constructor(licensePlate) {
this.licensePlate = licensePlate;
if(new.target === Vehicle) { // "伪抽象基类(不能直接实例化)"
throw new Error('Vehicle cannot be directly instantiated');
}
if(!this.foo) { // 子类必须定义某个方法
throw new Error('Inheriting class must define foo()');
}
}
identifyPrototype(id) {
console.log( id, this );
}
static identifyClass(id) {
console.log( id, this );
}
}
class Bus extends Vehicle {
// constructor() {} // ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor
// 定义的constructor函数体内必须得调用super() 或者 返回一个对象; 如果要访问this,必须先调用super();
// constructor() { return {};}
/*constructor() {
// this.name = "test"; // ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor
super();
console.log( this instanceof Vehicle );
}*/ static identifyClass(id) {
console.log( id, 'overwrite', this );
} foo() {}
}
// let v = new Vehicle(); // Error: Vehicle cannot be directly instantiated
let b = new Bus('1337H4X'); // Error: Inheriting class must define foo()
// new Bus(); // true b.identifyPrototype('bus'); // bus Bus { licensePlate: '1337H4X' } // bus Bus {}
// v.identifyPrototype('vehicle'); // vehicle Vehicle {} Bus.identifyClass('bus'); // bus overwrite [class Bus extends Vehicle]
Vehicle.identifyClass('vehicle'); // vehicle [class Vehicle] // 类混入
let FooMixin = (Superclass) => class extends Superclass {
foo() {
console.log( 'foo' );
}
};
let BarMixin = (Superclass) => class extends Superclass {
bar() {
console.log( 'bar' );
}
};
let BazMixin = (Superclass) => class extends Superclass {
baz() {
console.log( 'baz' );
}
}; function mix(BaseClass, ...Minxins) {
return Minxins.reduce((accumulator, current) => current(accumulator), BaseClass);
} class Bus1 extends mix(Vehicle, BazMixin, BarMixin, FooMixin){};
let bb1 = new Bus1();
bb1.foo(); // foo
bb1.bar(); // bar
bb1.baz(); // baz class TestSuper {
foo() {
console.log( 'instance super.foo' );
}
static foo() {
console.log( 'super.foo' );
}
}
class TestSub extends TestSuper{
foo() {
super.foo();
console.log( 'instance sub.foo' );
}
static foo() {
super.foo();
console.log( 'sub.foo' );
}
}
let sub = new TestSub();
sub.foo();
// instance super.foo
// instance sub.foo
TestSub.foo();
// super.foo
// sub.foo

JavaScript高级程序设计笔记08 对象、类与面向对象编程的更多相关文章

  1. JavaScript高级程序设计笔记之面向对象

    说起面向对象,大部分程序员首先会想到 类 .通过类可以创建许多具有共同属性以及方法的实例或者说对象.但是JavaScript并没有类的概念,而且在JavaScript中几乎一切皆对象,问题来了,Jav ...

  2. Javascript高级程序设计笔记(很重要尤其是对象的设计模式与继承)

    var obj = {'a':'a'}; var fun = function (){} console.log(typeof obj);//object console.log(typeof fun ...

  3. javascript高级程序设计--笔记01

    概述 JavaScript的实现包含三个部分: 1  核心(ECMAScript)   提供核心语言功能 2  文档对象模型(DOM)  一套提供了访问以及操作网页内容的API 3  浏览器对象模型( ...

  4. JavaScript高级程序设计笔记(一)

    ---恢复内容开始--- 前三章为基础知识,为了方便以后查看,所以比较啰嗦.这里对函数的基本操作没有记录. 1.JavaScript的实现 虽然 JavaScript 和 ECMAScript 通常都 ...

  5. JavaScript高级程序设计之location对象

    location对象用来处理URL的相关信息 1.获取查询字符串 // 获取查询字符串对象 var getQueryStringArgs = function () { ? location.sear ...

  6. JavaScript高级程序设计之window对象

    在浏览器中window对象实现了JavaScript中的Global对象: window对象是最顶层的对象: 所有其他全局的东西都可以通过它的属性检索到. ; window.aa = ; // 所有全 ...

  7. JavaScript高级程序设计笔记 事件冒泡和事件捕获

    1.事件冒泡 要理解事件冒泡,就得先知道事件流.事件流描述的是从页面接收事件的顺序,比如如下的代码: <body> <div> click me! </div> & ...

  8. 读javascript高级程序设计05-面向对象之创建对象

    1.工厂模式 工厂模式是一种常用的创建对象的模式,可以使用以下函数封装创建对象的细节: function CreatePerson(name,age){ var p=new Object(); p.n ...

  9. 读javascript高级程序设计06-面向对象之继承

    原型链是实现继承的主要方法,通过原型能让一个引用类型继承另一个引用类型. 1.原型链实现继承 function SuperType(){ this.superprop=1; } SuperType.p ...

  10. JavaScript高级程序设计之原型对象

    构造函数.原型对象.构造器是一体的关系,同时产生: 实例中的隐藏属性__proto__指向原型对象: 原型对象是这四种关系的纽带. 原型对象是动态的,不论在何处变化,实例中可以立即体现出来. var ...

随机推荐

  1. 2021-8-5 Microsoft文档学习笔记(C#)

    以下列表概述了类可以包含的成员类型. 常量:与类相关联的常量值 字段:与类关联的变量 方法:类可执行的操作 属性:与读取和写入类的已命名属性相关联的操作 索引器:与将类实例编入索引(像处理数组一样)相 ...

  2. Windows 环境下载、安装、使用(.Net 5.0) Redis 数据库及常见问题的解决

    〇.前言 Redis (Remote Dictionary Server 远程字典服务)是一个使用 ANSI C 编写的开源.包含多种数据结构,支持网络.基于内存.可选持久性的键值对存储数据库,是现在 ...

  3. 使用kubeadm部署kubernetes

    k8s版本:1.15.0 前期准备 节点: master:172.50.13.103(2核2G) node-1:172.50.13.104(2核2G) node-2:172.50.13.105(2核2 ...

  4. Redis系列18:过期数据的删除策略

    Redis系列1:深刻理解高性能Redis的本质 Redis系列2:数据持久化提高可用性 Redis系列3:高可用之主从架构 Redis系列4:高可用之Sentinel(哨兵模式) Redis系列5: ...

  5. Go/C++/Java中的数组对比

    数组是大多数编程语言中的基本数据结构.然而,不同的编程语言对数组的实现和语义有所不同.以下是 Go.C++ 和 Java 中数组的主要区别: 1. 基本性质 Go: 数组是值类型.赋值或将数组传递给函 ...

  6. 用ChatGPT三分钟免费做出数字人视频- 提升自媒体魅力

    本教程收集于:AIGC从入门到精通教程汇总 操作指引 ChatGPT产生文案=>腾讯智影数字人播报=>粘贴文案=>导出视频. 说明:部分资源只有会员才能用~,非会员可生成5分钟视频. ...

  7. openNebula集群搭建

    openNebula集群搭建 目录 openNebula集群搭建 OpenNebula概述 环境介绍及部署前准备 1. 安装步骤 1.关闭防火墙 2.配置epel源地和opennebula源 3.安装 ...

  8. MySQL实战实战系列 04 深入浅出索引(上)

    提到数据库索引,我想你并不陌生,在日常工作中会经常接触到.比如某一个 SQL 查询比较慢,分析完原因之后,你可能就会说"给某个字段加个索引吧"之类的解决方案.但到底什么是索引,索引 ...

  9. 四千行代码写的桌面操作系统GrapeOS完整代码开源了

    简介 学习操作系统原理最好的方法是自己写一个简单的操作系统. GrapeOS是一个非常简单的x86多任务桌面操作系统,源代码只有四千行,非常适合用来学习操作系统原理. 源码地址:https://git ...

  10. Teamcenter RAC 开发之《AbstractRendering》

    背景 关于Teamcenter RAC 客制化渲染表单,做一两个有时间做还是可以的,问题是大批量做的时候就会存在很多重复的代码 例如: 1.定义很多 TCProperty,JTextFiled,ite ...