js原型
2019-11-22 hubo JavaScript
原型和继承:
原型(Prototype)是 JavaScript 中最容易搞混的概念,其中一个原因是prototype可以用在两个不同的情形下。
-
原型关系
每一个对象都有一个prototype对象,里面包含了所有它的原型的属性。
.__proto__是一个不正规的机制(ES6 中提供),用来获取一个对象的 prototype。你可以理解为它指向对象的parent。
所有普通的对象都继承.constructor属性,它指向该对象的构造函数。当一个对象通过构造函数实现的时候,__proto__属性指向构造函数的构造函数的.prototype。Object.getPrototypeOf()是 ES5 的标准函数,用来获取一个对象的原型。 -
原型属性
每一个函数都有一个.prototype属性,它包含了所有可以被继承的属性。该对象默认包含了指向原构造函数的.constructor属性。每一个使用构造函数创建的对象都有一个构造函数属性。
接下来通过例子来帮助理解:
function Dog(breed, name) { (this.breed = breed), (this.name = name); } Dog.prototype.describe = function() { console.log(`${this.name} is a ${this.breed}`); }; const rusty = new Dog("Beagle", "Rusty");
/* .prototype 属性包含了构造函数以及构造函数中在prototype上定义的属性。*/ console.log(Dog.prototype); // { describe: ƒ , constructor: ƒ }
/* 使用Dog构造函数构造的对象 */ console.log(rusty); // { breed: "Beagle", name: "Rusty" } /* 从构造函数的原型中继承下来的属性或函数 */ console.log(rusty.describe()); // "Rusty is a Beagle" /* .__proto__ 属性指向构造函数的.prototype属性 */ console.log(rusty.__proto__); // { describe: ƒ , constructor: ƒ } /* .constructor 属性指向构造函数 */ console.log(rusty.constructor); // ƒ Dog(breed, name) { ... } |
JavaScript 的使用可以说相当灵活,为了避免出 bug 了不知道,不妨接入Fundebug线上实时监控。
原型链:
原型链是指对象之间通过 prototype 链接起来,形成一个有向的链条。当访问一个对象的某个属性的时候,JavaScript 引擎会首先查看该对象是否包含该属性。如果没有,就去查找对象的 prototype 中是否包含。以此类推,直到找到该属性或则找到最后一个对象。最后一个对象的 prototype 默认为 null。
拥有 vs 继承
一个对象有两种属性,分别是它自身定义的和继承的。
function Car() {} Car.prototype.wheels = 4; Car.prototype.airbags = 1;
var myCar = new Car(); myCar.color = "black";
/* 原型链中的属性也可以通过in来查看: */ console.log("airbags" in myCar); // true console.log(myCar.wheels); // 4 console.log(myCar.year); // undefined
/* 通过hasOwnProperty来查看是否拥有该属性: */ console.log(myCar.hasOwnProperty("airbags")); // false — Inherited console.log(myCar.hasOwnProperty("color")); // true |
Object.create(obj) 创建一个新的对象,prototype 指向obj。
var dog = { legs: 4 }; var myDog = Object.create(dog);
console.log(myDog.hasOwnProperty("legs")); // false console.log(myDog.legs); // 4 console.log(myDog.__proto__ === dog); // true |
继承是引用传值:
继承属性都是通过引用的形式。我们通过例子来形象理解:
var objProt = { text: "original" }; var objAttachedToProt = Object.create(objProt); console.log(objAttachedToProt.text); // original
// 我们更改objProt的text属性,objAttachedToProt的text属性同样更改了 objProt.text = "prototype property changed"; console.log(objAttachedToProt.text); // prototype property changed
// 但是如果我们讲一个新的对象赋值给objProt,那么objAttachedToProt的text属性不受影响 objProt = { text: "replacing property" }; console.log(objAttachedToProt.text); // prototype property changed |