博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
了解JavaScript原型链
阅读量:7022 次
发布时间:2019-06-28

本文共 3060 字,大约阅读时间需要 10 分钟。

一个原型链

  • 通过 构造函数A 创建的实例A-instance的`[[proto]]`属性会自动指向 构造函数A的原型对象`prototype`,这种关系是在实例被创建时便自动创建的。
  • 而我们的 构造函数A 的原型对象 `prototype` 本身就是一个 `Object`的实例。

JavaScript动态特性的副作用

function car(){this.broken = true;}const carA = new car();car.prototype.WhetherBroken = function(){return this.broken;}console.log(carA.WhetherBroken()); // output:car.prototype = {  //line 1expensive: function(){return true; }}console.log(carA.WhetherBroken()); // output: trueconst carB = new car();console.log(carB.expensive()); // output: true;console.log(carB.WhetherBroken()); // Uncaught TypeError: carB.WhetherBroken is not a function复制代码

  • 当我们创建实例carA时,原型链的状态

  • 当我们在 line 1修改了构造函数car的原型,例carB时原型链的样子。

  • 当我们对构造函数car原型上的属性和方法进行删改时, car的所有实例都可以访问新的方法或属性。
  • 当我们完全更换构造函数car的原型时(如line1), 之前创建的car的实例会保留旧的原型的引用, 而在更换完原型之后通过构造函数创建的实例将会保留新的原型的引用。对新的原型上的属性的删改在旧的实例(保留旧的原型的引用的实例)上无法体现。

通过instanceof判断实例类型

function Car(){};const carA = new Car();console.log(carA instanceof Car); // line 1  output: trueCar.prototype = {}; // line 2console.log(carA instanceof Car); // line 3 output:  false复制代码

  • 用法: object instanceof constructor
  • 原理: instanceof 通过判断构造函数constructor的prototype是否在object的原型链上。即检测右边函数原型是否在左侧对象的原型链上。

  • line 2 之前

  • line2 改变构造函数`Car`的原型之后原型链的样子

  • 如图所示, 显然构造函数Car的原型是不在CarA的原型链上的
  • 同时我们还发现, 尽管我们在 line 2 重新定义了构造函数Car的原型, 但是新定义的原型对象并没有consturctor属性, 而原来的原型对象的constructor属性仍然指向构造函数Car。
  • 这就会产生如下问题:

console.log(carA.constructor === Car);// output:trueconsole.log(carA instanceof Car); // output:false复制代码

  • 而通过原型链实现继承时, 也会出现类似的问题:

function Car(){}function miniCar(){}miniCar.prototype = new Car();// line 1let miniA = new miniCar();console.log( miniA.constructor === miniCar); // falseconsole.log( miniA instanceof miniCar); //trueconsole.log( miniA.constructor); //Car复制代码

  • 原型继承的图示

  • 由于javascript 的垃圾回收机制, 实际情况应是如下图所示

  • 为了解决上述问题, 我们应该在上述代码 line1 之后设置新原型的constructor属性

function Car(){}function miniCar(){}miniCar.prototype = new Car();// line 1Object.defineProperty(miniCar.prototype, 'constructor', {enumerable: false,value: miniCar,writable: true}) // added linelet miniA = new miniCar();console.log( miniA.constructor === miniCar); // trueconsole.log( miniA instanceof miniCar); //trueconsole.log( miniA.constructor); //miniCar复制代码
  • 由此我们也通过JavaScript实现了原型继承

function SuperClass(){};function SubClass(){};SubClass.prototype = new SuperClass();Object.defineProperty(SubClass.prototype, 'constructor', {enumerable: false,value: SubClass,writable: true})let instance = new SubClass();复制代码

ES6 Class

  • 由于ES5实现原型继承的过程繁琐复杂, ES6引入class语法糖, 来模拟类继承。 但其底层仍然是基于原型的实现。
// before ES6function Car(name){ //构造函数this.name;}Car.showName = function(car){//静态方法return car.name;}Car.prototype.run = function(){ //原型方法return true;}function miniCar(){};miniCar.prototype = new Car('BMW');Object.defineProperty(SubClass.prototype, 'constructor', {eumerable: false,value:SubClass,writable: true,})// after ES6class Car {constructor(name){ // 构造函数this.name; }// 静态方法static showName(car){return car.name; }// 如下为原型方法 run(){return true; }}// 通过 extends 关键字来实现继承。class miniCar extends Car{//...}复制代码

转载于:https://juejin.im/post/5ae6d3c16fb9a07ac90cfba9

你可能感兴趣的文章
Myeclipse2014 激活 (包括方法和工具)
查看>>
兼容的网页宽度margin padding
查看>>
Git中的文件状态和使用问题解决
查看>>
架空线路导地线力学计算
查看>>
[转]服务器自动化操作 RunDeck
查看>>
服务没有mysql
查看>>
如何实例化i2c_client(四法)
查看>>
【Vegas原创】EXCEL光标所在的行自动变色
查看>>
Angularjs在线api文档
查看>>
IPAddress
查看>>
一个PHP操作大变量的例子
查看>>
SQL Server中,Numric,Decimal,Money三种字段类型的区别
查看>>
Debugging Chromium on Windows
查看>>
分享几个.NET WinForm开源组件,纪念逐渐远去的WinForm。。。
查看>>
使用EntitysCodeGenerate
查看>>
Magicodes.WeiChat——ASP.NET Scaffolding生成增删改查、分页、搜索、删除确认、批量操作、批量删除等业务代码...
查看>>
CSDN-markdown编者LaTex数学公式
查看>>
air mobile andriod ios 页面加载控件
查看>>
js中的fadeIn()
查看>>
R树空间索引
查看>>