文章目录
总结
- 原型的理解:每个函数对象都有原型对象,构造函数生成实例时,该属性会称为实例对象的原型,原型对象用来定义所有实例共享的属性的方法。
- 原型链的理解:每个对象都有
__proto__
属性,指向其构造函数的原型对象。构造函数的原型对象也是对象,也有自己的__proto__
属性,由此形成原型链。对象方法查找时,在本身找不到时,向原型链上找。
js 继承机制的设计思想是,原型对象的所有属性和方法,都能被实例对象共享。 也就是说,如果属性和方法定义在原型上,那么所有实例对象都能共享,不仅节省了内存,还体现了实例对象之间的联系。
函数 prototype 属性的作用
js 规定,每个函数都有一个 prototype 属性,指向一个对象。
function f() {}
typeof f.prototype // "object"
- 对于普通函数来说,该属性基本无用。但是,对于构造函数来说,生成实例的时候,该属性会自动成为实例对象的原型。
- 原型对象的属性不是实例对象自身的属性。只要修改原型对象,变动就立刻会体现在所有实例对象上。
- 如果实例对象自身就有某个属性或方法,它就不会再去原型对象寻找这个属性或方法。
总结一下,原型对象的作用,就是定义所有实例对象共享的属性和方法。 这也是它被称为原型对象的原因,而实例对象可以视作从原型对象衍生出来的子对象。
prototype 的验证方法
isPrototypeOf()
对象方法,判断某个 prototype 对象和某个实例之间的关系。
alert(Cat.prototype.isPrototypeOf(cat1)); //true
hasOwnProperty()
对象方法,判断某一个属性是本地属性还是继承自 prototype 的属性。
alert(cat1.hasOwnProperty("name")); // true
in 操作符
判断某个实例是否含有某个属性,不管是不是本地属性。
alert("name" in cat1); // true
in 运算符还可以用来遍历某个对象的所有属性。
获得原型对象的方法
obj.__proto__
obj.constructor.prototype
Object.getPrototypeOf(obj)
前两种都不是很可靠。__proto__
属性只有浏览器才需要部署,其他环境可以不部署。而 obj.constructor.prototype 在手动改变原型对象时,可能会失效。推荐第三种。
原型链
JavaScript 规定,所有对象都有自己的原型对象(prototype)
。一方面,任何一个对象,都可以充当其他对象的原型;另一方面,由于原型对象也是对象,所以它也有自己的原型。因此,就会形成一个“原型链”(prototype chain):对象到原型,再到原型的原型……
如果一层层地上溯,所有对象的原型最终都可以上溯到 Object.prototype,即 Object 构造函数的 prototype 属性。也就是说,所有对象都继承了 Object.prototype 的属性
。这就是所有对象都有 valueOf
和 toString
方法的原因,因为这是从 Object.prototype 继承的。Object.prototype 的原型是 null。null 没有任何属性和方法,也没有自己的原型。因此,原型链的尽头就是 null
。
constructor 属性
prototype 对象有一个 constructor 属性,默认指向 prototype 对象所在的构造函数。
constructor 属性的作用是,可以得知某个实例对象,到底是哪一个构造函数产生的。(通过 name 属性,从实例得到构造函数的名称。)另一方面,有了 constructor 属性,就可以从一个实例对象新建另一个实例。(箭头函数没有 constructor)
修改原型对象时,一般要同时修改 constructor 属性的指向。
instanceof 运算符
instanceof 运算符的左边是实例对象,右边是构造函数。它会检查右边构建函数的原型对象(prototype),是否在左边对象的原型链上。
特殊情况:有一种特殊情况,就是左边对象的原型链上,只有 null 对象。这时,instanceof 判断会失真。
对于 undefined 和 null,instanceOf 运算符总是返回 false。
Function instanceof Object;//true
Function.__proto__ == Function.prototype;
Function.prototype.__proto == Object.prototype;
Object instanceof Function;//true
Object.__proto__ = Function.prototype;
继承
单继承
用组合继承的方法或 extend
多继承
// 继承 M1
S.prototype = Object.create(M1.prototype);
// 继承链上加入 M2
Object.assign(S.prototype, M2.prototype);
// 指定构造函数
S.prototype.constructor = S;