私有变量和函数
Javascript中是没有块级作用域的,但是有函数作用域。在函数内部定义的变量和函数是私有的,不能被外界访问到。
function Foo(){
//私有变量
var name='A';
//私有函数
var fn=function(){
return 'fn';
}
console.log('inside: name:' + name); //inside: name:A
console.log('inside: fn:' + fn()); //inside: fn:fn
}
Foo();
console.log('outside: name:' + name); //Uncaught TypeError: name is not defined
console.log('outside: fn:' + fn()); //Uncaught TypeError: fn is not a function(…)
静态变量和函数
当定义一个函数后通过点号 “.”为其添加的属性和函数,通过对象本身仍然可以访问得到,但是其实例却访问不到,这样的变量和函数分别被称为静态变量和静态函数。
function Person(){
//静态变量
Person.eye= 2;
//静态函数
Person.say=function(){
console.log('Hello');
}
};
Person();
console.log(Person.eye);//2
Person.say();//Hello
var Tom= new Person();
console.log(Tom.eye);//undefined
Tom.say();//Uncaught TypeError: Tom.say is not a function(…)
实例变量和函数
在面向对象编程中除了一些库函数我们还是希望在对象定义的时候同时定义一些属性和方法,实例化后可以访问,JavaScript也能做到这样
function Person(){
//实例变量
this.eye=2;
//实例方法
this.say=function(){
console.log('Hello');
}
}
var Tom = new Person();
console.log(Tom.eye);//2
Tom.say();//Hello
prototype的由来
下例中,我们发现实例中改变了属性,并不影响另外一个实例。两个实例中的属性方法名相同,但不是一个引用,而是对Person对象定义的属性和方法的复制。
但是对于方法而言,完全一样的功能但复制了无数份,显然不科学。于是,prototype应运而生。
function Person(){
this.name=[];
this.say=function(){
console.log('Hello');
}
}
var Tom = new Person();
Tom.name.push('Tom');
console.log(Tom.name);//["Tom"]
console.log(typeof Tom.name);//object
var Jerry= new Person();
console.log(Jerry.name);//[]
Jerry.name.push('Jerry');
console.log(Jerry.name);//["Jerry"]
prototype的基本概念
创建函数时,会自动创建一个名为prototype(原型对象)的属性,它的用途是包含所有实例共享的属性和方法。prototype调用构造函数创建对象实例的原型对象。
prototype中除了有构造函数,还有一个属性 __proto__
,它指向创建它的函数对象的prototype
var Person=function(){};
Person.prototype.name='super man';
Person.prototype.say=function(){
console.log('Hello');
}
var Tom = new Person();
console.log(Tom.name);//super man
Tom.name= 'Tom';
console.log(Tom.name);//Tom
var Jerry= new Person();
console.log(Jerry.name);//super man
Jerry.say(); //Hello
在调用Jerry.say()
时,Jerry没有这个方法,于是会沿着Jerry的__proto__
(指向的是Person的prototype)向上查找,找到了say()
方法,于是执行。
原型及原型链
var Person=function(name){
this.name=name;
};
Person.prototype.say=function(){
console.log('Hello, I am ' + this.name);
}
var person1 = new Person('Byron');
person1.say(); //Hello, I am Byron
var person2= new Person('Frank');
person2.say(); //Hello, I am Frank
我们把这个有__proto__
串起来的直到Object.prototype.__proto__
为null的链叫做原型链。
原型继承
function Father(){
this.familyname='Lee';
}
Father.prototype.getFamilyName = function(){
console.log('My family name is ' + this.familyname);
}
function Son(){
this.age=1;
}
Son.prototype= new Father();
var Tom = new Son();
console.log(Tom.familyname); //Lee
实现继承的核心就是Son.prototype= new Father();
,为什么这样就实现了继承呢?我们通过框图来理解。
上文中提到,实例对象(此处为new Father())的__proto__
指向的是创建它的函数对象的prototype(此处为Father.prototype
),于是能访问到Father.prototype
中的getFamilyName
方法。Son.prototype
等价于 new Father()
,则Son.prototype.__proto__
等价于 new Father()
的__proto__
。于是Son和Fahter之间产生了继承的关系。
当实例化一个Son时(上代码中为Tom),Tom的__proto__
指向Son.prototype
,Son.prototype
中的__proto__
指向Father.prototype
,Father.prototype
中含有getFamilyName
方法。
强调一下:函数对象有prototype
属性,普通对象没有prototype
,但有__proto__
属性