您的位置:首页 > 移动开发

JavaScript:prototype&apply&call

2014-12-28 23:50 746 查看

一、JavaScript中的三种方法:

function People(name){
  this.name=name;
  //对象方法
  this.Introduce=function(){
    alert("My name is "+this.name);
  }
}
//类方法
People.Run=function(){
  alert("奔跑吧兄弟!");
}
//原型方法
People.prototype.IntroduceChinese=function(){
  alert("我的名字是"+this.name);
}
 
//测试
var p1=new People("ligang");
p1.Introduce();
People.Run();
p1.IntroduceChinese();


二、定义类

JavaScript中的函数都是以值的形式出现的,方法和字段之间没有太大的区别。如果属性值是函数,那么这个属性就被定义为一个方法;否则,它只是一个普通的属性或字段。

原型对象:其属性被类的所有实例所继承,如果原型对象的属性值是函数的话,这个函数就作为类的实例的方法来调用。

JavaScript中定义类的步骤可以缩减为三步:

第一步,先定义一个构造函数,并设置初始化新对象的实例属性;

第二步,给构造函数的prototype对象定义实例的方法;

第三步,给构造函数定义类字段和类属性。

/**
 * constructor:用以设置实例的属性的函数
 * methods:实例的方法,复制至原型中
 * statics:类属性,复制至构造函数中
 */
function defineClass(constructor,methods,statics){
	if(methods) extend(constructor.prototype,methods);
	if(statics) extend(constructor,static);
	return constructor;
}

三、类扩充

JavaScript中基于原型的继承机制是动态的:对象从其原型继承属性,如果创建对象之后原型的属性发生改变,也会影响到继承这个原型的所有实例对象。这意味着我们可以通过给原型对象添加新方法来扩充JavaScript类。JS中允许的类型有Array, Boolean, Date, Enumerator, Error, Function, Number, Object, RegExp,
String。在实例上不能使用prototype,否则发生编译错误。

类.prototype.方法名=function(){};

四、类继承

JavaScript 是基于对象的,任何元素都可以看成对象。然而,类型和对象是不同的。通常来说,javascript中的对象就是一个指向prototype的指针和一个自身的属性列表。javascript创建对象时采用了写时复制的理念。

A.prototype = new B();

prototype继承是通过把子类的原型对象(prototype)设置成父类的一个实例来进行继承的。

要实现继承,就必须保证A继承B以后,A所做的修改不能影响到B以及继承自B的其它对象。A.prototype = new B();这个方法,是创建了一个新的对象{},并且继承了B的原型,这是一个新对象,不是和B同一引用,所以不会污染B。

prototype继承也有四个比较明显的缺点:

  缺点一:父类的构造函数不是像J***A中那样在给子类进行实例化时执行的,而是在设置继承的时候执行的,并且只执行一次。这往往不是我们希望的,特别是父类的构造函数中有一些特殊操作的情况下。

  缺点二:由于父类的构造函数不是在子类进行实例化时执行,在父类的构造函数中设置的成员变量到了子类中就成了所有实例对象公有的公共变量。由于JavaScript中继承只发生在“获取”属性的值时,对于属性的值是String,Number和Boolean这些数据本身不能被修改的类型时没有什么影响。但是Array和Object类型就会有问题。

  缺点三:如果父类的构造函数需要参数,我们就没有办法了。

  缺点四:子类原本的原型对象被替换了,子类本身的constructor属性就没有了。在类的实例取它的constructor属性时,取得的是从父类中继承的constructor属性,从而constructor的值是父类而不是子类。

五、call和apply方法

call与apply的第一个参数都是需要调用的函数对象,在函数体内这个参数就是this的值,剩余的参数是需要传递给函数的值,call与apply的不同就是call传的值可以是任意的,而apply传的剩余值必须为数组。

/*定义一个人类*/  
function Person(name,age){  
    this.name=name;  
    this.age=age;  
}  
/*定义一个学生类*/  
function Student(name,age,grade) {  
    Person.apply(this,arguments);  
    Person.call(this,name,age);// 二者完全等价
    this.grade=grade;  
}  
//创建一个学生类  
var student=new Student("zhangsan",21,"一年级");
Person.apply(this,arguments);

this:在创建对象在这个时候代表的是student

arguments:是一个数组,也就是[“zhangsan”,”21”,”一年级”];也就是通俗一点讲就是:用student去执行Person这个类里面的内容,在Person这个类里面存在this.name等之类的语句,这样就将属性创建到了student对象里面

将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。说简单一点,这两函数的作用其实就是更改对象的内部指针,即改变对象的this指向的内容。这在面向对象的js编程过程中有时是很有用的。

五、实例

function baseClass(){
    this.showMsg = function(){
        alert("baseClass::showMsg");   
    }
   
    this.baseShowMsg = function(){
        alert("baseClass::baseShowMsg");
    }
}
baseClass.showMsg = function(){
    alert("baseClass::showMsg static");
}

function extendClass(){
    this.showMsg =function (){
        alert("extendClass::showMsg");
    }
}
extendClass.showMsg = function(){
    alert("extendClass::showMsg static")
}

extendClass.prototype = new baseClass();
var instance = new extendClass();

instance.showMsg(); //显示extendClass::showMsg
instance.baseShowMsg(); //显示baseClass::baseShowMsg
instance.showMsg(); //显示extendClass::showMsg

baseClass.showMsg.call(instance);//显示baseClass::showMsg static 

var baseinstance = new baseClass();
baseinstance.showMsg.call(instance);//显示baseClass::showMsg  意思是将instance看成baseinstance,调用showMsg方法
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: