JavaScript 原型链中的主要知识概念:原型,构造函数,实例,proto,prototype,instanceOf,constructor。
所有的对象在默认的情况下都有一个原型,并且继承该原型上的属性。原型也是一个对象,它自身也有一个原型。
JavaScript 中没有对函数和构造函数进行区分。每一个函数都有一个 prototype (原型)属性,这个属性是一个指针,指向一个对象,即原型对象,原型对象上的属性和方法,能被函数的实例所共享。
构造函数通过 new 生成一个实例对象,该实例对象具有一个__proto__
属性,指向原型对象。并且与其构造函数的 prototype 属性指向的是同一个对象。
instanceOf 方法,用来判断对象是否为构造函数的一个实例。
obj instanceof Object
// 返回 true,false
constructor 属性返回对象的构造函数。(返回值是函数的引用,不是函数名)
创建对象的方式
创建对象的三种方式:
// 字面量
var o1 = { name : "o1"};
// 或
var o1 = new Object({ name: "o1"});
// 构造函数
function M (name) {
this.name = name;
}
var o2 = new M("o2");
// Object.create()
var o3 = Object.create({name: "o3"})
console.log(o1)
console.log(o2)
console.log(o3)
由打印结果可知,前两种方式创建的对象,其原型是 Object。Object.create(obj)
方法,会生成一个空对象,并将传入的参数对象 obj 作为该空对象的原型对象。
原型链
原型链:一个实例对象 A,是由构造函数基于原型对象创建的,通过 prototype 属性可查找到其原型对象 B,再往上查找,又有创造 B 的原型对象,以此类推,一直查找到 Object.prototype
为止,Object.prototype
是整个原型链的顶端。原型对象的查找,是通过 prototype
和 __proto__
属性来实现向上查找的。
由上图可知,获取对象原型的方法有:
var a = {};
//Firefox 3.6, Chrome 5 and Safari 4
a.__proto__; //[object Object]
//all browsers
a.constructor.prototype; //[object Object]
另外还可以利用 ES6 中的 Object.getPrototypeOf()
来获取对象的原型:
//Firefox 3.6 and Chrome 5
Object.getPrototypeOf(a); //[object Object]
Object.getPrototypeOf() 方法返回指定对象的原型(内部[[Prototype]]属性的值)
一个构造函数的原型对象,其构造器即为构造函数本身。
function M (name) {
this.name = name;
}
var o2 = new M("o2");
// M.prototype即为M的原型对象
M.prototype.constructor === M // true,由于M为一个构造函数,M原型对象的构造器即为M
// o2._proto_即为o2的原型对象
o2.__proto__ === M.prototype // true
函数才有 prototype
属性,由于函数也是对象,所以函数也有 __proto__
属性。
// 函数M,是构造函数Function的一个实例
M.__proto__ === Function.prototype // true
原型对象上的方法,可以被其实例使用。
.
function M (name) {
this.name = name;
}
var o2 = new M("o2");
o2 instanceof M // true
o2 instanceof Object // true
o2.__proto__ === M.prototype // true,指向同一个原型对象
M.prototype.__proto__ === Object.prototype // true
Object.prototype 指向 o2 原型对象的原型(o2 的二阶原型对象),所以 o2 instanceof Object 为 true。
.
那么如何判断,一个实例对象,是构造函数的实例,还是继承自原型对象的实例呢?
由原型链图可知,一个对象的原型通过 constructor 指向该对象的构造函数。
o2.__proto__.constructor === M // true
o2.__proto__.constructor === Object // false
一个构造函数的原型对象,其构造器即为构造函数本身。
.
“在构造函数内的绑定操作优先级,永远高于在原型上的绑定操作优先级。”
如,在构造函数内和原型上都定义了一个方法,构造器内的方法会覆盖原型上的方法。
function Person () {
this.name = 'jean'
}
Person.prototype.name = 'test'
var man = new Person()
console.log(man.name) // 'jean'
在实际开发中,我们经常用 hasOwnProperty()
这个方法,来检查给定的属性在当前对象实例中(而不是实例的原型中)是否存在。因为利用普通 obj.key 的形式获取对象属性时,会先在对象本身获取该属性,若未查到,则到该对象的原型上去查找,一直向上查到 key 值或查到原型对象为 Object.prototype 为止。
网友评论