ES6之前是没有类的概念的,都是通过构造函数来解决问题。现在绝大部分浏览器都支持ES6。
1-创建实例对象:
创建实例对象有三种方法。
1.new Object()
var a=new Object;
2.字面量
var a={};
3.构造函数
var a=function(){
this.name='zhangsan';
this.sing=function(){alert('正在唱歌');}}
var b=new a;
通过new创建实例对象,首先看到new后会开辟一个空间,然后构造函数里面的this都会指向这个空间,里面的属性和方法都会放到这个空间里面,放完后就返回这个空间,这个空间就变成了我们定义的对象。
2-实例成员和静态成员
.1.实例成员
构造函数里通过this.来写的属性和方法都是实例成员,这些成员都可以在外部通过定义的对象.属性或方法来访问。
2.静态成员
构造函数里面没有通过this来写得属性和方法都是静态的,这些无法通过实例化的对象拿到。只能通过构造函数本身来拿到。
构造函数实例化后,会造成内存浪费,那么需要通过原型来解决。
3-prototype对象
每个构造函数都有一个属性指向这个prorotype对象,所以这个对象中的属性和方法都被构造函数所拥有。因此为了避免内存浪费,我们把那些不变的方法定义在prorotype对象里面。
总结:把属性放到构造函数里面,方法放到prorotype对象里面。
当然这边还存在一个问题,当把方法定义到原型对象里面,构造函数就没有定义这个方法,我们实例化对象后,实例完的对象可以直接调用这个方法,这里就涉及到对象的一个属性_proto_。
4-_proto_属性
对象里面都有一个_proto_属性,且这个属性的指向和构造函数里面的prorotype属性的指向是一样的,都是指向原型对象。因此可以使用构造函数里的原型方法。
5-construction
原型对象里面有一个属性construction,这个属性指回构造函数本身。如果我们给原型对象赋值,就会出现下面的这种情况,这时候手动给原型对象添加construction属性,让属性指回构造函数。
假设有一个构造函数a,原型里面有方法b和c,然后往原型赋值方法b和c,即a.prototype={
b,c};那么这个原型对象不再指向构造函数,因为赋值完的原型对象里面不再有construction属性。
6-原型链
只要是对象都有原型,同理原型对象的原型是什么呢?答案那就是Object._proto_。那么这个大写的Object的原型对象是谁创造出来的?当然是Object这个构造函数。接着分析,接着奏乐,Object的原型对象指向谁呢?Null为空即返回结果为空。
因为有了原型链,所以可以从下往上查找对象成员。
7-成员查找机制
当访问一个对象的属性和方法时,首先看看这个对象自身有没有该东西,没有就看看这个对象的原型,也就是_proto_指向的对象,如果没有的话就找原型对象的原型即obeject构造函数的原型对象。再没有就没有了,因为找下去就为空,就找不到了。
8-this指向问题
构造函数中的this和原型对象里面的方法的this都是指向调用者。
9-原型对象的应用
利用原型对象可以对内置对象如数组添加自定义方法。
Array.prototype.名字=function(){},然后就可以直接使用了。如果用对象形式添加方法则要手动指回去构造函数。
10-call()
这个方法可以调用函数,更强大的是可以改变方法的this指向。
11-继承
因为ES6之前,没有像类那些extend继承父类的属性和方法,是通过构造函数继承属性,原型对象继承方法来实现继承。
下面代码继承属性。
function Father (uname,age){
this.uname=uname;
this.age=ageh;
}
function Son(uname,age){
Father.call(this,uname,age)
}
下面是方法继承。
function Father(){};
Father.prototype.sing();
function Son(){};
如果Son要继承Father里面的sing则把父亲的原型对象赋值给Son的原型对象。
Son.prototype=Father.prototype;
通过赋值来继承的话,会出现改变儿子的原型指向问题,那么这两个构造函数的原型是同一个,显然没有达到预期的需求。那么怎么解决?就是把Father实例后赋值给Son的原型就可以达到效果。即下面的代码。
function Father(){};
Father.prototype.sing();
function Son(){};
Son.prototype=new Father;