构造函数,原型和实例的关系:
每个构造函数(constructor)都有一个原型对象(prototype),原型对象都包含一个指向构造函数的指针,而实例(instance)都包含一个指向原型对象的内部指针。
__proto__和prototype的区别
prototype 只有函数才有的属性 __proto__是每一个对象都有的属性
原型链
由于 __proto__是任何对象都有的属性,而js,万物皆对象,所以会形成一条__proto__连起来的链条,递归访问__proto__必须最终到头,并且值为null。
- 一般来说,__proto__ === constructor.prototype
- 当访问一个属性,会首先检索自身的属性,若自身没有,则会沿着__proto__向上寻找,一层一层地寻找,直到寻到
null,这里的原型链就是实例对象的__proto__属性。
function A(name){
this.test = name;
};
A.prototype.getName = function () {
return console.log(this.test);
}
var a = new A('a');
function B() {};
// B.prototype.constructor = B; // 注意这个
B.prototype = new A('b');
var c = new B();
这是没有设置B.prototype.constructor = B的各种情况的结果;
c.constructor === function A(name) {
this.test = name;
}
B.prototype.constructor === function A(name) {
this.test = name;
}
B.constructor === function Function() { [native code] }
a.__proto__ === A { getName: [Function] }
new B().__proto__ === A { test: 'b' }
B.prototype === A { test: 'b' }
c.__proto__ === A { test: 'b' }
B.__proto__ === function () { [native code] }
A.__proto__ === function () { [native code] }
B.prototype.__proto__ === A { getName: [Function] }
设置B.prototype.constructor = B的各种情况的结果; (之所以要设置B.prototype.constructor = B,是为了使B的实例在原型链上不混乱)
c.constructor === function B() {}
B.prototype.constructor === function B() {}
B.constructor === function Function() { [native code] }
a.__proto__ === A { getName: [Function] }
new B().__proto__ === B { test: 'b', constructor: [Function: B] }
B.prototype === B { test: 'b', constructor: [Function: B] }
c.__proto__ === B { test: 'b', constructor: [Function: B] }
B.__proto__ === function () { [native code] }
A.__proto__ === function () { [native code] }
B.prototype.__proto__ === A { getName: [Function] }
修改构造函数原型,对实例的影响
-
在new之前修改,无影响
-
在new之后修改
function Foo() {} Foo.prototype.flag = 123; function fn() {} //先new实例 var foo = new Foo(); var f = new fn(); //先再改变原型指向 Foo.prototype = f; console.dir(foo);//Foo console.log(foo.__proto__ === f);//false foo的原型链不会因为构造函数原型的变化而变化。 console.log(Foo.prototype === f);//true console.log(foo instanceof Foo);//false console.log(foo.__proto__ === Foo.prototype);//falsea. 实例产生之后,修改构造函数的原型,对实例不造成影响,因为实例化之后,修改构造函数原型,并不会改变实例对象指向的原来的构造函数的原型,也就是说,原来的构造函数原型还存在内存里面。修改后的构造函数原型可视为一个新的构造函数,不对以前实例化的对象产生影响。
b. instanceof 实在原型链上查找,看是否能找到构造函数的原型,即判断__proto__属性与构造函数的prototype属性是否相等。从a可看出,很明显是不等。