javascript 原型链及其继承

2023-06-05 0 272

javascript 原型链及其继承

依照规范化不提议间接采用 __proto__,所推荐采用 Object.getPrototypeOf(),但是为的是措词方便快捷方法论明晰,下面都以 __proto__ 替代。

特别注意下面的讲法,蓝本上的方式和特性被承继 到新第一类中,并并非被导入到新第一类,他们看下面那个范例。

// 德卿杨 function Foo(name) { this.name = name; } Foo.prototype.getName = function() { return this.name; } Foo.prototype.length = 3; let foo = new Foo(muyiy); // 相等于 foo.__proto__ = Foo.prototype console.dir(foo);
javascript 原型链及其继承

蓝本上的特性和方式表述在 prototype 第一类上,而非第一类示例这类。当出访两个第一类的特性 / 方式时,它更为重要在该第一类上搜寻,还会搜寻该第一类的蓝本,和该第一类的蓝本的蓝本,几层几层向下搜寻,直至找出两个英文名字相匹配的特性 / 方式或抵达蓝本链的结尾(null)。

比如说初始化 foo.valueOf() 会出现甚么?

具体来说检查和 foo 第一类与否具备需用的 valueOf() 方式。假如没,则检查和 foo 第一类的蓝本第一类(即 Foo.prototype)与否具备需用的 valueof() 方式。假如没,则检查和 Foo.prototype 所对准的第一类的蓝本第一类(即 Object.prototype)与否具备需用的 valueOf() 方式。这儿有那个方式,只好该方式被初始化。
javascript 原型链及其继承

prototype 和 __proto__

上篇文章介绍了 prototype 和 __proto__ 的区别,其中蓝本第一类 prototype 是构造函数的特性,__proto__ 是每个示例上都有的特性,这两个并不一样,但 foo.__proto__ 和 Foo.prototype 对准同两个第一类。

这次他们再深入一点,蓝本链的构建是依赖于 prototype 还是 __proto__ 呢?

javascript 原型链及其继承

kenneth-kin-lum.blogspot.com/2012/10/jav…

Foo.prototype 中的 prototype 并没构建成一条蓝本链,其只是对准蓝本链中的某一处。蓝本链的构建依赖于 __proto__,如上图通过 foo.__proto__ 对准 Foo.prototype,foo.__proto__.__proto__ 对准 Bichon.prototype,如此几层几层最终链接到 null。

可以这么理解 Foo,我是两个 constructor,我也是两个 function,我身上有着 prototype 的 reference,只要随时初始化 foo = new Foo(),我就会将 foo.__proto__ 对准到我的 prototype 第一类。

不要采用 Bar.prototype = Foo,因为这不会执行 Foo 的蓝本,而是对准函数 Foo。 因此蓝本链将会回溯到 Function.prototype 而并非 Foo.prototype,因此 method 方式将不会在 Bar 的蓝本链上。

// 德卿杨 function Foo() { return foo; } Foo.prototype.method = function() { return method; } function Bar() { return bar; } Bar.prototype = Foo; // Bar.prototype 对准到函数 let bar = new Bar(); console.dir(bar); bar.method(); // Uncaught TypeError: bar.method is not a function 复制代码
javascript 原型链及其继承

instanceof 原理及实现

instanceof 运算符用来检测 constructor.prototype 与否存在于参数 object 的蓝本链上。

// 德卿杨 function C(){} function D(){} var o = new C(); o instanceof C; // true,因为 Object.getPrototypeOf(o) === C.prototype o instanceof D; // false,因为 D.prototype 不在 o 的蓝本链上 复制代码

instanceof 原理就是几层几层搜寻 __proto__,假如和 constructor.prototype 相等则返回 true,假如一直没搜寻成功则返回 false。

instance.[__proto__…] === instance.constructor.prototype 复制代码

知道了原理后他们来实现 instanceof,代码如下。

// 德卿杨 function instance_of(L, R) {//L 表示左表达式,R 表示右表达式 var O = R.prototype;// 取 R 的显示蓝本 L = L.__proto__;// 取 L 的隐式蓝本 while (true) { // Object.prototype.__proto__ === null if (L === null) return false; if (O === L)// 这儿重点:当 O 严格等于 L 时,返回 true return true; L = L.__proto__; } } // 测试 function C(){} function D(){} var o = new C(); instance_of(o, C); // true instance_of(o, D); // false 复制代码

蓝本链承继

蓝本链承继的本质是重写蓝本第一类,代之以两个新类型的示例。如下代码,新蓝本 Cat 不仅有 new Animal() 实例上的全部特性和方式,并且由于对准了 Animal 蓝本,所以还承继了Animal 蓝本上的特性和方式。

// 德卿杨 function Animal() { this.value = animal; } Animal.prototype.run = function() { return this.value + is runing; } function Cat() {} // 这儿是关键,创建 Animal 的示例,并将该示例赋值给 Cat.prototype // 相等于 Cat.prototype.__proto__ = Animal.prototype Cat.prototype = new Animal(); var instance = new Cat(); instance.value = cat; // 创建 instance 的自身特性 value console.log(instance.run()); // cat is runing 复制代码

蓝本链承继方案有以下缺点:

1、多个示例对引用类型的操作会被篡改2、子类型的蓝本上的 constructor 特性被重写了3、给子类型蓝本添加特性和方式必须在替换蓝本之后4、创建子类型示例时无法向父类型的构造函数传参

问题 1

蓝本链承继方案中,蓝本实际上会变成另两个类型的示例,如下代码,Cat.prototype 变成了 Animal 的两个示例,所以 Animal 的示例特性 names 就变成了 Cat.prototype 的特性。

而蓝本特性上的引用类型值会被所有示例共享,所以多个示例对引用类型的操作会被篡改。如下代码,改变了 instance1.names 后影响了 instance2。

// 德卿杨 function Animal(){ this.names = [“cat”, “dog”]; } function Cat(){} Cat.prototype = new Animal(); var instance1 = new Cat(); instance1.names.push(“tiger”); console.log(instance1.names); // [“cat”, “dog”, “tiger”] var instance2 = new Cat(); console.log(instance2.names); // [“cat”, “dog”, “tiger”] 复制代码

问题 2

子类型蓝本上的 constructor 特性被重写了,执行 Cat.prototype = new Animal() 后蓝本被覆盖,Cat.prototype 上丢失了 constructor 特性, Cat.prototype 对准了 Animal.prototype,而

Animal.prototype.constructor 对准了 Animal,所以 Cat.prototype.constructor 对准了 Animal。Cat.prototype = new Animal(); Cat.prototype.constructor === Animal // true 复制代码
javascript 原型链及其继承

解决办法就是重写 Cat.prototype.constructor 特性,对准自己的构造函数 Cat。

// 德卿杨 function Animal() { this.value = animal; } Animal.prototype.run = function() { return this.value + is runing; } function Cat() {} Cat.prototype = new Animal(); // 新增,重写 Cat.prototype 的 constructor 特性,指向自己的构造函数 Cat Cat.prototype.constructor = Cat; 复制代码
javascript 原型链及其继承

问题 3

给子类型蓝本添加特性和方式必须在替换蓝本之后,原因在第二点已经解释过了,因为子类型的蓝本会被覆盖。

// 德卿杨 function Animal() { this.value = animal; } Animal.prototype.run = function() { return this.value + is runing; } function Cat() {} Cat.prototype = new Animal(); Cat.prototype.constructor = Cat; // 新增 Cat.prototype.getValue = function() { return this.value; } var instance = new Cat(); instance.value = cat; console.log(instance.getValue()); // cat 复制代码

特性遮蔽

改造下面的代码,在 Cat.prototype 上添加 run 方式,但是 Animal.prototype 上也有两个 run 方式,但是它不会被出访到,这种情况称为特性遮蔽 (property shadowing)。

// 德卿杨 function Animal() { this.value = animal; } Animal.prototype.run = function() { return this.value + is runing; } function Cat() {} Cat.prototype = new Animal(); Cat.prototype.constructor = Cat; // 新增 Cat.prototype.run = function() { return cat cat cat; } var instance = new Cat(); instance.value = cat; console.log(instance.run()); // cat cat cat 复制代码

那如何出访被遮蔽的特性呢?通过 __proto__ 初始化蓝本链上的特性即可。

// 接上 console.log(instance.__proto__.__proto__.run()); // undefined is runing 复制代码

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务