Javascript对象创建

来源:互联网 发布:angularroute.js下载 编辑:程序博客网 时间:2024/04/29 03:48

本文参考张龙老师和Java1234视频教程

方法的定义

function fn1(name){    alert(name+"1");}function fn1(name,age){    alert(name+"2");}fn1("zs");

比如上面的脚本中调用fn1之后,最后调用的是第二个,这该如何理解

var fn1 = function(name){    alert(name+"1");};var fn1 = function(name,age){    alert(name+"2");};fn1("zs");

方法的定义可以理解成上面这个代码片段,刚开始fn1指向第一个,然后fn1指向第二个
然后调用fn1的时候就会 调用第二个。

原理部分:定义函数,其实就是等于定义一个对象,通过Function来定义,下面以例子来解释

var fn1 = new Function("name","alert(name+"+1+");");var fn1 = new Function("name","age","alert(name+"+2+");");fn1("zs");

Function 对象中可以接受的参数是不定的,但是有一个规则:最后一个参数一定是方法体

从上面可以看出来其实每个方法其实也是个Function对象,也就是说方法本身也是个对象,所以 返回一个方法是很正常的,就等于返回个对象这样

方法的特性

既然说函数是对象,对象一般都有属性和方法,比如每个方法都有一个length属性,这个属性指的是 这个函数期望接受的参数个数,说到这里要提到一个特殊的用法arguments。arguments指的是函数实际接受的参数封装成的数组。

function fn1(){     }alert(fn1());

上面的语法片段会打印 undefined,也就是说没有返回值的情况,就会返回undefined
在这里提一下,其实undefined是从null派生出来的,也就是说如果一个var a==undefined是true,那么a肯定==null也是true。
nul和undefined的深层次区别 参考:http://developer.51cto.com/art/201401/426966.htm

对象的创建

参考W3C中JavaScript

  • 最原始方法
var oCar = new Object;oCar.color = "blue";//也可以oCar["color"] = "blue";oCar.showColor = function() {  alert(this.color);};

这个是最原始的,他有一点特别不好,如果想创建一百个对象,就要写一百遍这样的代码,所以产生了工厂方式

  • 工厂方式
function createCar(sColor,iDoors,iMpg) {  var oTempCar = new Object;  oTempCar.color = sColor;  oTempCar.showColor = function() {    alert(this.color);  };  return oTempCar;}var oCar1 = createCar("red",4,23);var oCar2 = createCar("blue",3,25);oCar1.showColor();      //输出 "red"oCar2.showColor();      //输出 "blue"

这里最好的是把函数搞成共享的,把函数写到外面,然后把showColor指向那个函数即可。从功能上讲,这样解决了重复创建函数对象的问题;但是从语义上讲,该函数不太像是对象的方法。所有这些问题都引发了开发者定义的构造函数的出现。

  • 构造函数方式
functon show(){   alert(this.color);}function Car(sColor,iDoors,iMpg) {  this.color = sColor;  this.showColor = show;  //this指向调用者}var oCar1 = new Car("red",4,23);var oCar2 = new Car("blue",3,25);

在执行第一行代码前先创建一个对象,只有用 this 才能访问该对象。然后可以直接赋予 this 属性,默认返回值也是this,这种方式比起工厂方式就更像后台语言定义类了

  • 原型方式
function Car() {}Car.prototype.color = "blue";Car.prototype.showColor = function() {  alert(this.color);};var oCar1 = new Car();var oCar2 = new Car();

在这段代码中,首先定义构造函数(Car),其中无任何代码。接下来的几行代码,通过给 Car 的 prototype 属性添加属性去定义 Car 对象的属性。调用 new Car() 时,原型的所有属性都被立即赋予要创建的对象,意味着所有 Car 实例存放的都是指向 showColor() 函数的指针。从语义上讲,所有属性看起来都属于一个对象,因此解决了前面两种方式存在的问题。

alert(oCar1 instanceof Car);    //输出 "true"

非常重要的一点是,通过原型定义的字段和方法都是所有事例共享的,就类似于JAVA的静态方法

  • 混合的构造函数/原型方式
function Car(sColor,iDoors,iMpg) {  this.color = sColor;  this.drivers = new Array("Mike","John");}Car.prototype.showColor = function() {  alert(this.color);};var oCar1 = new Car("red",4,23);var oCar2 = new Car("blue",3,25);oCar1.drivers.push("Bill");alert(oCar1.drivers);   //输出 "Mike,John,Bill"alert(oCar2.drivers);   //输出 "Mike,John"

这个就是利用上面两个综合产生的最经典方式。当然后面还有根据这个进行的扩展动态原型,但是个人认为哪个没有这种混合的看的更清晰。所以我最推荐这种

修改对象

这个我感觉W3C里面讲的太经典了。http://www.w3school.com.cn/js/pro_js_object_modifying.asp

对象的继承

对象继承分为两种,其中一个是对象冒充 一个是原型

  • 对象冒充
function ClassA(sColor) {    this.color = sColor;    this.sayColor = function () {        alert(this.color);    };}function ClassB(sColor) {    this.newMethod = ClassA;    this.newMethod(sColor);    delete this.newMethod;}

所有新属性和新方法都必须在删除了新方法的代码行后定义。否则,可能会覆盖超类的相关属性和方法:
其实这个只要懂this就非常好理解。 var b =new ClassB(“red”).当进入this.newMethod = ClassA后就是给b(也就是this)添加了一个新的变量,这个变量指向ClassA方法。 this.newMethod(sColor); 这句话就是调用这个方法(这也说明刚注册的方法就可以调用),调用这个方法后,在ClassA中里面的this就是classB的this,也就是b,这样到最后b就拥有了color属性和sayColor方法

但是对象冒充有一个缺点就是,ClassA中的原型 属性和方法,ClassB却继承不了

方法的call
all() 方法是与经典的对象冒充方法最相似的方法。它的第一个参数用作 this 的对象。其他参数都直接传递给函数自身。例如:

function sayColor(sPrefix,sSuffix) {    alert(sPrefix + this.color + sSuffix);};var obj = new Object();obj.color = "blue";sayColor.call(obj, "The color is ", "a very nice color indeed.");

上面这种obj就等于sayColor中的this,后面就是参数对应

function ClassA(sColor) {    this.color = sColor;    this.sayColor = function () {        alert(this.color);    };}function ClassB(sColor) {   ClassA.call(this, sColor);}var b =new ClassB();

过程
1、var b=new ClassB();
然后进入ClassB,首先隐式创建一个对象,这个对象就是this,也是返回的对象

2、ClassA.call(this, sColor);
this就是b,然后进入ClassA方法,classA方法中的this就是传入的this,也即是b,这样就完成了 继承。

apply()方法和call类似,只是传参数的时候不一样。
ClassA.call(this, sColor)==ClassA(this,new Array(sColor));

ClassA.call(this, sColor,name)==ClassA(this,new Array(sColor,name));

  • 原型方式实现继承
function ClassA() {}ClassA.prototype.color = "blue";ClassA.prototype.sayColor = function () {    alert(this.color);};function ClassB() {}ClassB.prototype = new ClassA();

记住标准写法是传ClassA的空的构造函数
这种方式真是太巧妙了,让ClassB.prototype等于ClassA的一个实例
这样凡是ClassB的实例都享有ClassA的静态方法和变量

因为标准是new ClassA的空的构造函数 所有这种方式只能继承ClassA的静态的变量和字段(也就是原型字段)

  • 混合方式
function ClassA(sColor) {    this.color = sColor;}ClassA.prototype.sayColor = function () {    alert(this.color);};function ClassB(sColor, sName) {    ClassA.call(this, sColor);    this.name = sName;}ClassB.prototype = new ClassA();ClassB.prototype.sayName = function () {    alert(this.name);};

这样经典的继承也就产生了。

0 0