TypeScript高级用法的知识点汇总(2)

在extendStatics方法内部虽然代码量相对较多,但是不难发现其实还是主要为了兼容ES5版本的执行环境。在ES6中新增了Object.setPrototypeOf方法用于手动设置对象的原型,但是在ES5的环境中我们一般通过一个非标准的__proto__属性来进行设置,Object.setPrototypeOf方法的原理其实也是通过该属性来设置对象的原型,其实现方式如下:

Object.setPrototypeOf = function(obj, proto) { obj.__proto__ = proto; return obj; }

在extendStatics(d, b)方法中,d指子类Child,b指父类Parent,因此该方法的作用可以解释为:

// 将子类Child的__proto__属性指向父类Parent Child.__proto__ = Parent;

可以将这行代码理解为构造函数的继承,或者叫静态属性和静态方法的继承,即属性和方法不是挂载到构造函数的prototype原型上的,而是直接挂载到构造函数本身,因为在JS中函数本身也可以作为一个对象,并可以为其赋予任何其他的属性,示例如下:

function Foo() { this.x = 1; this.y = 2; } Foo.bar = function() { console.log(3); } Foo.baz = 4; console.log(Foo.bar()) // -> 3 console.log(Foo.baz) // -> 4

因此当我们在子类Child中以Child.someProperty访问属性时,如果子类中不存在就会通过Child.__proto__寻找父类的同名属性,通过这种方式来实现静态属性和静态方法的路径查找。

第二部分:

在第二部分中仅包含以下两行代码:

function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());

其中d指子类Child,b指父类Parent,这里对于JS中实现继承的几种方式比较熟悉的同学可以一眼看出,这里使用了寄生组合式继承的方式,通过借用一个中间函数__()来避免当修改子类的prototype上的方法时对父类的prototype所造成的影响。我们知道,在JS中通过构造函数实例化一个对象之后,该对象会拥有一个__proto__属性并指向其构造函数的prototype属性,示例如下:

function Foo() { this.x = 1; this.y = 2; } const foo = new Foo(); foo.__proto__ === Foo.prototype; // -> true

对于本例中,如果通过子类Child来实例化一个对象之后,会产生如下关联:

const child = new Child(); child.__proto__ === (Child.prototype = new __()); child.__proto__.__proto__ === __.prototype === Parent.prototype; // 上述代码等价于下面这种方式 Child.prototype.__proto__ === Parent.prototype;

因此当我们在子类Child的实例child对象中通过child.someMethod()调用某个方法时,如果在实例中不存在该方法,则会沿着__proto__继续往上查找,最终会经过父类Parent的prototype原型,即通过这种方式来实现方法的继承。

基于对以上两个部分的分析,我们可以总结出以下两点:

// 表示构造函数的继承,或者叫做静态属性和静态方法的继承,总是指向父类 1. Child.__proto__ === Parent; // 表示方法的继承,总是指向父类的prototype属性 2. Child.prototype.__proto__ === Parent.prototype;

2、访问修饰符

TypeScript为我们提供了访问修饰符(Access Modifiers)来限制在class外部对内部属性的访问,访问修饰符主要包含以下三种:

public:公共修饰符,其修饰的属性和方法都是公有的,可以在任何地方被访问到,默认情况下所有属性和方法都是public的。

private:私有修饰符,其修饰的属性和方法在class外部不可见。

protected:受保护修饰符,和private比较相似,但是其修饰的属性和方法在子类内部是被允许访问的。

我们通过一些示例来对几种修饰符进行对比:

class Human { public name: string; public age: number; public constructor(name: string, age: number) { this.name = name; this.age = age; } } const man = new Human('tom', 20); console.log(man.name, man.age); // -> tom 20 man.age = 21; console.log(man.age); // -> 21

在上述示例中,由于我们将访问修饰符设置为public,因此我们通过实例man来访问name和age属性是被允许的,同时对age属性重新赋值也是允许的。但是在某些情况下,我们希望某些属性是对外不可见的,同时不允许被修改,那么我们就可以使用private修饰符:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/a5cd6f57eef1c0c30548e3ad454fcdf6.html