JavaScript初阶(五)-------- 原型
原型
原型是function对象的一个属性,它定义了构造函数制造出的对象的公共祖先。通过该构造函数产生的对象,可以继承该原型的属性和方法。原型也是对象。所以我们也能对它们进行增删改查。
function Person() { } Person.prototype.name = "xiaoming"; Person.prototype.age = 10; Person.prototype.sex = "male"; var person1 = new Person();
首先我们知道person1是构造函数Person( ) 构造出来的,所以person1继承了Person的原型,看看运行结果
我们需要特别注意一下,person1上面的属性是只读的,不能修改它原型上的属性,也不能够删除。
原型的使用
在使用构造函数进行初始化的时候,我们往往在赋予新的函数的特征时,只是改变部分属性,而相同的部分就是重复执行,如之前的生产汽车
function Car(color){ this.name = "daben"; this.size = "big"; this.color = color; } var car1 = new Car('green"); var car2 = new Car("red");
上面我们用构造函数得出的两个新的对象car1,car2的时候,有两条语句重复执行,也就是耦合的,这时候我们就需要解耦,就要用到原型了
Car.prototype.name = "daben"; Car.prototype.size = "big"; function Car(color){ this.color = color; } var car1 = new Car('green"); var car2 = new Car("red");
原型基本的用途就是提取公有属性,共有的,重复的,能够提取出来的,放在原型上面,而私有的个性化的属性,就可以放在函数里面,每次执行就只执行个性化的。这样就减小了耦
合,大大提高了程序执行效率。总而言之,原型就是一个对象,每一个函数有且只有一个原型。
原型的继承(原型链)
构造函数创建对象的时候,里面有一个__proto__的属性,它指向的是该函数的原型,当访问变量的时候,如果自身没有该属性,它就会寻找__proto__上面指向的该函数的原型上去
寻找,如果这个原型上面也没有,会继续沿着原型上面的proto属性继续寻找,这条链式结构,就称之为原型链,每条原型链的终点就是Object。如果,在原型链终点上面也没有找到查询的
变量就会报undefined。
Constructor构造器
当我们使用构造函数构造对象时,会有一个constructor属性,例如:
function Car(name){ this.name = name; this.size = "big"; } var car1 = new Car("daben");
我们再来看看运行结果
从结果中可以看出constructor指向的是构造出这个对象的函数func Car(name)。
而当我们用自定义的方法设定原型的时候,constructor属性是没有的,例如:
Car.prototype = { name : "daben", size : "big" }//我们用自定义的方法设定原型 function Car(money) { this.money = money; } var car2 = new Car("10w")
结果是这样的
我们发现__proto__下面并没有constructor属性,所以我们需要手动添加constructor属性。这就是自定义原型和原生原型的区别了。
利用原型创建对象 object.create( )
object.create(prototype)
我们传进去的必须要是原型,如果我们传的是原始值就会报错。并且在这里我们需要特别注意,null没有原型。所以如果我们传进去的是null,系统不会报错,增删改查也能操作对象,
但是这个创建的对象没有原型,就会在运行的时候出现一些问题,比如当我们用document.write打印他的时候,因为对象是不能直接打印出来的,需要隐式的调用toString,然而没有原型
就不能使用toString方法,所以此时会报错。
只有使用Object.create的时候才能把null传进去,其他情况手动的将prototype设定为null都是不好使的。
面试题:所有对象的终端指向object.prototype是错误的,绝大多数才是对的,因为null没有原型。
与this指向有关的call 和 apply
当我们用构造函数创建对象的时候,可以使用call和apply改变构造函数里面的this指向,例如
function Person() { this.name = "hj"; this.age = 20 } var obj = { }; Person.call(obj); obj // Object { name : "hj",age :20}
obj本来是个空对象,但是由于call使构造函数Person里面的this指向了obj,就相当于向obj对象里面添加了属性。
如果传入了参数,那么第一个就是this指向,后面的就是函数参数
Person.call(obj , 函数参数1,函数参数2);
Person.apply(obj,[函数参数1,函数参数2] );
他们两的区别就是传入参数的形式不同,我们往往都是用apply,因为我们可以用arguments来进行不定参操作
function Person(name,age){ this.name = name ; this.age = age; } var obj = { }; function test() { Person.apply(obj,arguments) } test('hj',20);
在多人项目开发中,当我们需要使用之前写好的代码块时,直接使用apply改变this指向。利用其他的方法构建自己的方法,提高代码运行效率。