js-20170819-prototype对象

1. 概述
1.1 构造函数的缺点
JavaScript 通过构造函数生成新对象,因此构造函数可以视为对象的模板。实例对象的属性和方法,可以定义在构造函数内部
function Cat(name, color) {
this.name = name;
this.color = color;
this.meow = function () {
console.log('mew, mew, mew...');
};
}
 
var cat1 = new Cat('大毛', '白色');
var cat2 = new Cat('二毛', '黑色');
 
cat1.meow === cat2.meow
// false
上面代码中,cat1和cat2是同一个构造函数的实例。但是,它们的meow方法是不一样的,就是说每新建一个实例,就会新建一个meow方法。这既没有必要,又浪费系统资源,因为所有meow方法都是同样的行为,完全应该共享。
1.2 prototype 属性的作用
JavaScript 的每个对象都继承另一个对象,后者称为“原型”(prototype)对象。只有null除外,它没有自己的原型对象
原型对象上的所有属性和方法,都能被派生对象共享。这就是 JavaScript 继承机制的基本设计
通过构造函数生成实例对象时,会自动为实例对象分配原型对象。每一个构造函数都有一个prototype属性,这个属性就是实例对象的原型对象
当实例对象本身没有某个属性或方法的时候,它会到构造函数的prototype属性指向的对象,去寻找该属性或方法。这就是原型对象的特殊之处
原型对象的作用,就是定义所有实例对象共享的属性和方法。这也是它被称为原型对象的原因,而实例对象可以视作从原型对象衍生出来的子对象
1.3 原型链
所有对象的原型最终都可以上溯到Object.prototype,即Object构造函数的prototype属性指向的那个对象。那么,Object.prototype对象有没有它的原型呢?回答可以是有的,就是没有任何属性和方法的null对象,而null对象没有自己的原型
“原型链”的作用是,读取对象的某个属性时,JavaScript 引擎先寻找对象本身的属性,如果找不到,就到它的原型去找,如果还是找不到,就到原型的原型去找。如果直到最顶层的Object.prototype还是找不到,则返回undefined
需要注意的是,一级级向上,在原型链寻找某个属性,对性能是有影响的。所寻找的属性在越上层的原型对象,对性能的影响越大。如果寻找某个不存在的属性,将会遍历整个原型链。
举例来说,如果让某个函数的prototype属性指向一个数组,就意味着该函数可以当作数组的构造函数,因为它生成的实例对象都可以通过prototype属性调用数组方法
1.4 constructor 属性
prototype对象有一个constructor属性,默认指向prototype对象所在的构造函数。
function P() {}
 
P.prototype.constructor === P
// true
由于constructor属性定义在prototype对象上面,意味着可以被所有实例对象继承。
 
 
2. instanceof 运算符
instanceof运算符返回一个布尔值,表示指定对象是否为某个构造函数的实例。
var v = new Vehicle();
v instanceof Vehicle // true
instanceof运算符的左边是实例对象,右边是构造函数。它会检查右边构建函数的原型对象,是否在左边对象的原型链上。因此,下面两种写法是等价的。
v instanceof Vehicle
// 等同于
Vehicle.prototype.isPrototypeOf(v)
 
 
3. Object.getPrototypeOf()
Object.getPrototypeOf方法返回一个对象的原型。这是获取原型对象的标准方法。
// 空对象的原型是Object.prototype
Object.getPrototypeOf({}) === Object.prototype
// true
 
// 函数的原型是Function.prototype
function f() {}
Object.getPrototypeOf(f) === Function.prototype
// true
 
// f 为 F 的实例对象,则 f 的原型是 F.prototype
var f = new F();
Object.getPrototypeOf(f) === F.prototype
// true
 
 
4. Object.setPrototypeOf()
Object.setPrototypeOf方法可以为现有对象设置原型,返回一个新对象。
Object.setPrototypeOf方法接受两个参数,第一个是现有对象,第二个是原型对象。
var a = {x: 1};
var b = Object.setPrototypeOf({}, a);
// 等同于
// var b = {__proto__: a};
 
b.x // 1
 
 
5. Object.create()
生成实例对象的常用方法,就是使用new命令,让构造函数返回一个实例。但是很多时候,只能拿到一个实例对象,它可能根本不是由构建函数生成的,那么能不能从一个实例对象,生成另一个实例对象呢?
JavaScript 提供了Object.create方法,用来满足这种需求。该方法接受一个对象作为参数,然后以它为原型,返回一个实例对象。该实例完全继承继承原型对象的属性。
下面三种方式生成的新对象是等价的。
var obj1 = Object.create({});
var obj2 = Object.create(Object.prototype);
var obj3 = new Object();
使用Object.create方法的时候,必须提供对象原型,即参数不能为空,或者不是对象,否则会报错。
 
 
6. Object.prototype.isPrototypeOf()
对象实例的isPrototypeOf方法,用来判断一个对象是否是另一个对象的原型。
var o1 = {};
var o2 = Object.create(o1);
var o3 = Object.create(o2);
 
o2.isPrototypeOf(o3) // true
o1.isPrototypeOf(o3) // true
上面代码表明,只要某个对象处在原型链上,isPrototypeOf都返回true。
Object.prototype.isPrototypeOf({}) // true
Object.prototype.isPrototypeOf([]) // true
Object.prototype.isPrototypeOf(/xyz/) // true
Object.prototype.isPrototypeOf(Object.create(null)) // false
上面代码中,由于Object.prototype处于原型链的最顶端,所以对各种实例都返回true,只有继承null的对象除外
 
 
7. Object.prototype.__proto__
__proto__属性(前后各两个下划线)可以改写某个对象的原型对象。
 
 
8. 获取原型对象方法的比较
__proto__属性指向当前对象的原型对象,即构造函数的prototype属性。
 
var obj = new Object();
obj.__proto__ === Object.prototype
// true
obj.__proto__ === obj.constructor.prototype
// true
获取实例对象obj的原型对象,有三种方法。
obj.__proto__
obj.constructor.prototype
Object.getPrototypeOf(obj)
推荐使用第三种Object.getPrototypeOf方法,获取原型对象。
var o = new Object();
Object.getPrototypeOf(o) === Object.prototype
// true
 
posted @ 2017-09-12 18:49  jialuchun  阅读(168)  评论(0编辑  收藏  举报