写在前面
我们知道所有引用类型默认都继承了Object,而这个继承也是通过原型链实现的,要记住,所有的默认原型都是Object的实例,因此默认原型都会包含一个内部指针,指向Object.prototype。这也正是所有自定义类型都会继承toString()、valueOf()等默认方法的根本原因。
var Fn = function() {}; Object.prototype.a = function() {}; Function.prototype.b = function() {}; var f = new Fn(); /*打印实例对象f的a属性,由原型链知, f.__proto__.__proto__==Object.prototype, 而a是Object.prototype的自定义类型,所以 f中也有a属性。*/ console.log(f.a) // ƒ () {} /* b为Function()构造器原型Function.prototype的 自定义属性,而a是Object.prototype的自定义类 型,Function.prototype.__proto__==Object.prototype, 所以没有联系,返回undefined */ console.log(f.b) // undefined /*构造函数Fn()是Function()的实例对象, 所以Fn.__proto__==Function.prototype, b为Function()构造器原型Function.prototype 的自定义属性*/ console.log(Fn.b) // ƒ () {} /*Fn.__proto__.__proto__==Function.prototype,*/ console.log(Fn.a) // ƒ () {}
实例二
function foo() { foo.a = function() { alert(1) }; this.a = function() { alert(2) }; a = function() { alert(3) }; var a = function() { alert(4) }; }; foo.prototype.a = function() { alert(5) }; foo.a = function() { alert(6) }; // 直接调用foo.a()函数,因为foo()没有调用,所以执行输出6 foo.a(); // 6 // 调用foo() var obj = new foo(); //this==>obj obj.a(); // 2 // 调用完foo()后,alert(1)会把alert(6)覆盖 foo.a(); // 1
实例三
var obj = { proto: { a: 1, b: 2 } }; function F() { }; F.prototype = obj.proto; var f = new F(); obj.proto.c = 3; obj.proto = { a: -1, b: -2 }; alert(f.a); // 1 alert(f.c); // 3 delete F.prototype['a']; alert(f.a); // undefined alert(obj.proto.a); // -1
分析:首先定义一个obj对象,其值为一个proto对象,后来定义一个F()的函数,,这时候obj和F()的原型指向同一个地址,然后给obj.proto增加一个c=3;所以obj改变了自然而然F()也改变的,F()中也存在c,后来obj把proto重新赋值一个新的对象,就是把obj的proto指向一个新的地址,但是修改后对F()的所有都不影响。
实例四
// 创建一个Foo函数 function Foo() { getName = function() { alert(1); } return this; } // 给Foo函数添加一个函数属性getName Foo.getName = function() { alert(2); } // 在Foo的原型上添加一个getName函数属性 Foo.prototype.getName = function() { alert(3); } // 以函数表达式的方式创建一个getName函数 var getName = function() { alert(4); } // 以函数声明的方式创建一个getName函数 function getName() { alert(5); } // 调用Foo.getName函数 Foo.getName(); //2 // 调用getName函数,预解析使得 “以函数声明的方式创建一个getName函数” 提前,然后 “以函数表达式的方式创建一个getName函数” 覆盖,输出为 4 getName(); // 4 // 调用 Foo函数,然后再调用其中的getName函数 Foo().getName(); // 1 // 调用 Foo函数后,getName有被覆盖掉,Foo中的getName由局部变成全局 getName(); // 1 // 创建 Foo.getName() 的实例 new Foo.getName() // 2 // 调用Foo(),返回this,指向window,然后调用window的getName new Foo().getName(); //3 // 理解 new this.getName this 指向 window new new Foo().getName(); //3