function Obj(){ var a=0; //私有变量 var fn=function(){ //私有函数 }}这样在函数对象Obj外部无法访问变量a和函数fn,它们就变成私有的,只能在Obj内部使用,即使是函数Obj的实例仍然无法访问这些变量和函数var o=new Obj();console.log(o.a); //undefinedconsole.log(o.fn); //undefined2、静态变量、函数
function Obj(){} Obj.a=0; //静态变量 Obj.fn=function(){ //静态函数 }console.log(Obj.a); //0console.log(typeof Obj.fn); //functionvar o=new Obj();console.log(o.a); //undefinedconsole.log(typeof o.fn); //undefined3、实例变量、函数function Obj(){ this.a=[]; //实例变量 this.fn=function(){ //实例方法}}console.log(typeof Obj.a); //undefinedconsole.log(typeof Obj.fn); //undefinedvar o=new Obj();console.log(typeof o.a); //objectconsole.log(typeof o.fn); //function这样可以达到上述目的,然而function Obj(){ this.a=[]; //实例变量 this.fn=function(){ //实例方法 }}var o1=new Obj();o1.a.push(1);o1.fn={};console.log(o1.a); //[1]console.log(typeof o1.fn); //objectvar o2=new Obj();console.log(o2.a); //[]console.log(typeof o2.fn); //function上面的代码运行结果完全符合预期,但同时也说明一个问题,在o1中修改了a和fn,而在o2中没有改变,由于数组和函数都是对象,是引用类型,这就说明o1中的属性和方法与o2中的属性与方法虽然同名但却不是一个引用,而是对Obj对象定义的属性和方法的一个复制。function f1(){}; var f2 = function(){}; var f3 = new Function("str","console.log(str)"); var o3 = new f1(); var o1 = {}; var o2 =new Object(); console.log(typeof Object); //function console.log(typeof Function); //function console.log(typeof o1); //object console.log(typeof o2); //object console.log(typeof o3); //object console.log(typeof f1); //function console.log(typeof f2); //function console.log(typeof f3); //function 在上面的例子中 o1 o2 o3 为普通对象,f1 f2 f3 为函数对象。怎么区分,其实很简单,凡是通过 new Function() 创建的对象都是函数对象,其他的都是普通对象。 f1,f2,归根结底都是通过 new Function()的方式进行创建的。Function Object 也都是通过 New Function()创建的。 function f1(){}; console.log(f1.prototype) //f1{} console.log(typeof f1.prototype) //Object console.log(typeof Function.prototype) // Function,这个特殊 console.log(typeof Object.prototype) // Object console.log(typeof Function.prototype.prototype) //undefined从这句console.log(f1.prototype) //f1 {} 的输出就结果可以看出,f1.prototype就是f1的一个实例对象(这里就是f1的原型对象)。就是在f1创建的时候,创建了一个它的实例对象并赋值给它的prototype,基本过程如下:var temp = new f1(); f1. prototype = temp;所以,Function.prototype为什么是函数对象就迎刃而解了,上文提到凡是new Function ()产生的对象都是函数对象,所以temp1是函数对象。
var temp1 = new Function (); Function.prototype = temp1;那原型对象是用来做什么的呢?主要作用是用于继承。举了例子:
var person = function(name){ this.name = name};person.prototype.getName = function(){ return this.name; // 这里this指向原型对象person ==>person.name}var xpg = new person(‘xiaopingguo");xpg.getName(); //xiaopingguo从这个例子可以看出,通过给person.prototype设置了一个函数对象的属性,那有person实例(例中:xpg)出来的普通对象就继承了这个属性。具体是怎么实现的继承,就要讲到下面的原型链了。function Person(){}
根据上图可以看出Person对象会自动获得prototyp属性,而prototype也是一个对象,会自动获得一个constructor属性,该属性正是指向Person对象。
当调用构造函数创建一个实例的时候,实例内部将包含一个内部指针(很多浏览器这个指针名字为_ proto _ )指向构造函数的prototype,这个连接存在于实例和构造函数的prototype之间,而不是实例与构造函数之间。
function Person(name){ this.name=name;}Person.prototype.printName=function(){ alert(this.name);}var person1=new Person("Byron");var person2=new Person("Frank");
Person的实例person1中包含了name属性,同时自动生成一个_ proto _属性,该属性指向Person的prototype,可以访问到prototype内定义的printName方法,大概就是这个样子的:

写段程序测试一下看看prototype内属性、方法是能够共享
function Person(name){ this.name=name;}Person.prototype.share=[];Person.prototype.printName=function(){ alert(this.name);}var person1=new Person("Byron");var person2=new Person("Frank");person1.share.push(1);person2.share.push(2);console.log(person2.share); //[1,2]果不其然!实际上当代码读取某个对象的某个属性的时候,都会执行一遍搜索,目标是具有给定名字的属性,搜索首先从对象实例开始,如果在实例中找到该属性则返回,如果没有则查找prototype,如果还是没有找到则继续递归prototype的prototype对象,直到找到为止,如果递归到object仍然没有则返回错误。同样道理如果在实例中定义如prototype同名的属性或函数,则会覆盖prototype的属性或函数。—-这就是Javascript的原型链。function Person(name){ this.name=name;}Person.prototype.share=[];var person=new Person("Byron");person.share=0;console.log(person.share); //0;而不是prototype中的[]6.原型链
原型链中属性查找:
当查找一个对象的属性时,JavaScript 会向上遍历原型链,直到找到给定名称的属性为止,到查找到达原型链的顶部 - 也就是 Object.prototype - 但是仍然没有找到指定的属性,就会返回 undefined,我们来看一个例子:
function foo() { this.add = function (x, y) { return x + y; }}foo.prototype.add = function (x, y) { return x + y + 10;}Object.prototype.subtract = function (x, y) { return x - y;}var f = new foo();alert(f.add(1, 2)); //结果是3,而不是13alert(f.subtract(1, 2)); //结果是-1通过代码运行,我们发现subtract是安装我们所说的向上查找来得到结果的,但是add方式有点小不同,这也是我想强调的,就是属性在查找的时候是先查找自身的属性,如果没有再查找原型,再没有,再往上走,一直插到Object的原型上,所以在某种层面上说,用 for in语句遍历属性的时候,效率也是个问题。function Foo() {}Foo.prototype = 1; // 无效7、构造函数、实例和原型对象的区别<script type="text/javascript"> function Animal(name) //积累构造函数 { this.name = name;//设置对象属性 } Animal.prototype.behavior = function() //给基类构造函数的prototype添加behavior方法 {alert("this is a "+this.name); } var Dog = new Animal("dog");//创建Dog对象 var Cat = new Animal("cat");//创建Cat对象 Dog.behavior();//通过Dog对象直接调用behavior方法 Cat.behavior();//output "this is a cat" alert(Dog.behavior==Cat.behavior);//output true;</script>8、原型的使用 var Calculator = function (decimalDigits, tax) { this.decimalDigits = decimalDigits; this.tax = tax; };然后,通过给Calculator对象的prototype属性赋值对象字面量来设定Calculator对象的原型。 Calculator.prototype = {add: function (x, y) {return x + y;},subtract: function (x, y) {return x - y;} }; //alert((new Calculator()).add(1, 3));我们就可以new Calculator对象以后,就可以调用add方法来计算结果了。Calculator.prototype = function () { add = function (x, y) {return x + y; }, subtract = function (x, y) {return x - y; } return {add: add,subtract: subtract }} ();//alert((new Calculator()).add(11, 3));同样的方式,我们可以new Calculator对象以后调用add方法来计算结果了。var BaseCalculator = function () { //为每个实例都声明一个小数位数 this.decimalDigits = 2;};//使用原型给BaseCalculator扩展BaseCalculator.prototype.add = function (x, y) { return x + y;};BaseCalculator.prototype.subtract = function (x, y) { return x - y;};声明了一个BaseCalculator对象,构造函数里会初始化一个小数位数的属性decimalDigits,然后通过原型属性设置2个function,分别是add(x,y)和subtract(x,y),当然你也可以使用前面提到的2种方式的任何一种,我们的主要目的是看如何将BaseCalculator对象设置到真正的Calculator的原型上。var BaseCalculator = function() { this.decimalDigits = 2;};BaseCalculator.prototype = { add: function(x, y) { return x + y; }, subtract: function(x, y) { return x - y; }};重写原型://覆盖前面Calculator的add() function Calculator.prototype.add = function (x, y) { return x + y + this.tax;};var calc = new Calculator();alert(calc.add(1, 1));这样,我们计算得出的结果就比原来多出了一个tax的值,但是有一点需要注意:那就是重写的代码需要放在最后,这样才能覆盖前面的代码。// 修改Object.prototypeObject.prototype.bar = 1; var foo = {goo: undefined};foo.bar; // 1"bar" in foo; // truefoo.hasOwnProperty("bar"); // falsefoo.hasOwnProperty("goo"); // true只有 hasOwnProperty 可以给出正确和期望的结果,这在遍历对象的属性时会很有用。 没有其它方法可以用来排除原型链上的属性,而不是定义在对象自身上的属性。var foo = { hasOwnProperty: function() { return false; }, bar: "Here be dragons"};foo.hasOwnProperty("bar"); // 总是返回 false// 使用{}对象的 hasOwnProperty,并将其上下为设置为foo{}.hasOwnProperty.call(foo, "bar"); // true当检查对象上某个属性是否存在时,hasOwnProperty 是唯一可用的方法。同时在使用 for in loop 遍历对象时,推荐总是使用 hasOwnProperty 方法,这将会避免原型对象扩展带来的干扰,我们来看一下例子:// 修改 Object.prototypeObject.prototype.bar = 1;var foo = {moo: 2};for(var i in foo) { console.log(i); // 输出两个属性:bar 和 moo}我们没办法改变for in语句的行为,所以想过滤结果就只能使用hasOwnProperty 方法,代码如下:// foo 变量是上例中的for(var i in foo) { if (foo.hasOwnProperty(i)) { console.log(i); //moo }}这个版本的代码是唯一正确的写法。由于我们使用了 hasOwnProperty,所以这次只输出 moo。如果不使用 hasOwnProperty,则这段代码在原生对象原型(比如 Object.prototype)被扩展时可能会出错。function Box(){ //大写,代表构造函数 Box.prototype.name = "trigkit4";//原型属性 Box.prototype.age = "21"; Box.prototype.run = function()//原型方法 {return this.name + this.age + "studying"; }}var box1 = new Box();var box2 = new Box();alert(box1.constructor);//构造属性,可以获取构造函数本身, //作用是被原型指针定位,然后得到构造函数本身_ proto _属性和prototype属性的区别function Box(){ //大写,代表构造函数 Box.prototype.name = "trigkit4";//原型属性 Box.prototype.age = "21"; Box.prototype.run = function()//原型方法 {return this.name + this.age + "studying"; }}var box1 = new Box();alert(box1.name);//trigkit4,原型里的值box1.name = "Lee";alert(box1.name);//Lee,就进原则var box2 = new Box();alert(box2.name);//trigkit4,原型的值,没有被box1修改构造函数的function Box(){this.name = "Bill";}Box.prototype.name = "trigkit4";//原型属性Box.prototype.age = "21";Box.prototype.run = function()//原型方法{return this.name + this.age + "studying";}var box1 = new Box();alert(box1.name);//Bill,原型里的值box1.name = "Lee";alert(box1.name);//Lee,就进原则综上,整理一下:function Person(){};Person.prototype.name = "trigkit4";Person.prototype.say = function(){ alert("Hi");}var p1 = new Person();//prototype是p1和p2的原型对象var p2 = new Person();//p2为实例化对象,其内部有一个__proto__属性,指向Person的prototypeconsole.log(p1.prototype);//undefined,这个属性是一个对象,访问不到console.log(Person.prototype);//Personconsole.log(Person.prototype.constructor);//原型对象内部也有一个指针(constructor属性)指向构造函数console.log(p1.__proto__);//这个属性是一个指针指向prototype原型对象p1.say();//实例可以访问到在原型对象上定义的属性和方法