JavaScript初学小结

来源:互联网 发布:淘宝与阿里巴巴的关系 编辑:程序博客网 时间:2024/05/29 02:29

最近的几周花了很多时间学习JavaScript 基础,以为有C++, C#基础,学起来应该挺快的,实际上大相径庭,之前的C++, C#的概念先入为主,  让我在理解 JS的类和对象时困惑了很久,直到我读到 IBM一个工程师的一篇文章《全面理解面向对象的 JavaScript》和w3cschools的解读,才总算理清了一点头绪。现把自己理解的东西重新整理下,理个头绪。

 

1. JS的类型:

  • JS的内置类型: undefined, null, boolean, string, number,  存放在栈中
  • 引用类型 object:把引用地址值存在栈中,内容存在堆中

 

 

2. 对象:

一开始,我一直很疑惑为什么是一个function既可以是一个普通的函数,又可以声明一个对象。

原来, 在JS中,对象是这么定义的: 对象是一组无序的属性集合,集合中每一项都由名称和值组成,而其中的值类型可能是内置类型,也可能是对象。

JS里面是没有类的概念的, function在作为一个构造器时,就相当于C++, C#里面的类, 构造器定义了其他对象的方法和属性,然后通过new方法生成新的对象。

要理解这个,需要来看下JS创建对象的多种方法:

 

2.1  原始的方式

var cat= newObject();cat.name="kitty";cat.weight = 10;cat.color = "white";cat.speak= function(){  alert("My name is " +this.name);};

创建了一只叫kitty的小猫,但是如果想创建一个叫别的名字的小猫就做不到了,所以,需要改进下。

 

2.2 工厂方式

function createCat(name, weight){  var cat= new Object();  cat.name=name;  cat.weight = weight;  cat.color ="white";  cat.speak= function(){    alert("My name is " +this.name);  };  return cat;}

这样,就可以创建多只小猫了,每个小猫都是不一样的,所以得给函数加上参数:

var cat1= createCat("kitty", 10);var cat2= createCat("MiMi", 20);

但是,这里会有一个问题,每次创建一只小猫都需要创建一个speak方法,比较理想的情况,这个cat.speak方法是可以多个对象共享的。 解决这个问题,需要把speak方法移到外面:

function speak(){  alert("my name is " +this.name);}function createCat(name, weight){  var cat= new Object();  cat.name=name;  cat.weight = weight;  cat.color ="white";  cat.speak= speak;  return cat;}

现在,可以通过createCat方法创建对象了。但是,每次创建对象都像一个函数附值,而且speak也不像是一个对象的方法,更像是一个独立的方法,怎么把它写得更面向对象一点呢?

 

2.3  构造函数

function speak(){  alert("my name is " +this.name);}function Cat(name, weight){  this.name=name;  this.weight = weight;  this.color = "white";  this.speak= speak;}var cat_1 = new Cat("Kitty", 10);var cat_2 = new Cat("Mimi",20);

这样,用C#的说法, 就可以通过new才创建新的Cat实例了。需要注意的是,Cat本身也是一个对象。

接下来解决一个问题,speak看上去像是一个独立的函数, 有没有办法让它看上去像对象自己的呢? 这需要用到JS里非常关键的Prototype原型的概念,这是JS里的核心部分,理解它就可以理解JS的对象和继承相关的用法。

 

2.4 原型方法+构造函数

function Cat(name, weight){  this.name=name;  this.weight = weight;  this.color = "white";}Cat.prototype.speak= function(){  alert("my name is " +this.name);};

在JS里,每个对象都有一个原型,构造函数对象CatCat所创建的对象所指向的原型都是同一个, 这里构造函数所创建的对象用__proto__属性指出原型, 构造函数对象Cat用prototype指出原型。所有对象的最终原型都是Object, JS就是在Object上定义valueOf, toString等属性的。 

var cat_1 = new Cat("Kitty",10);alert(cat_1.__proto__ === Cat.prototype); //true

最后,如果要把speak方法也定义在Cat里,可以利用一个初始化变量:

function Cat(name, weight){  this.name=name;  this.weight = weight;  this.color = "white";if (typeof(Cat.initialized) =="undefined"){      Cat.prototype.speak=function(){        alert("my name is " +this.name);      };    Cat.initialized = true;  }}


这么多种办法, 原型+构造函数的方式是更加推荐的。

最佳实践是:属性在构造函数里定义,方法在原型里定义。

 

所以说, JS的世界里,所有的都是对象,是另外一种思路的面向对象。下面可以比较下C++/C#等基于类的面向对象和JS基于原型的面向对象的不同:

 

基于类的面向对象方法

  

基于原型的面向对象方法

  

类+实例:类本身不是对象

  

原型的构造器和原型本身也是其他对象通过原型方法构造出来的对象

  

 对象的状态(变量)由对象实例持有,对象的行为由类持有,只有方法能够被继承

  

对象的行为,状态(变量)都属于对象本身,并且能够一起被继承

 

为了弥补无法使用全局函数和变量的不便,允许在类中声明static属性和静态方法

  

支持全局函数和变量,客观世界不存在静态概念,一切事物皆是对象

 

function  sayHello(){

   alert("hello");

}

 

sayHello.alternate=  function() {

   alert("hi");

}

 

sayHello();                //输出  "hello"

sayHello.alternate();        //输出  "hi"

 

既然JS是面向对象的,那就需要有封装,继承和多态的特点,JS是怎么实现这些的呢?

 

3. JS的面向对象

3.1 封装:私有和公有属性和方法

function Cat(name,weight){  //公共属性  this.name=name;  this.weight = weight;  //私有属性  var color ="white";  //私有方法  function getColor(){//这个是var getColor=function(){}的另一种写法    return color;  }  //公共方法  this.getColorService = function(){    return getColor();  }}//公共方法Cat.prototype.cry = function(){  alert("my name is " +this.name);};

 

3.2 继承

前面的创建对象的方法已经很多了, 所以实现继承的方法也一样, 具体可以参考w3cschools。 这里仅说对原型链方式的理解。

此例子实现一个Horse->Mammal -> Animal 的原型链继承:

function Animal(){ this.name="animal";  this.weight=0;  this.eat=function(){  alert(this.name + " is eatingsomething");  };}function Mammal(width){ this.name="manmal";  this.weight= 1;  this.width=width;}Mammal.prototype= new Animal();function Horse(height, weight,width){  Mammal.call(this, width);  //通过call方法,就可以把构造函数参数传递给原型对象   this.name="hores";  this.height=height;  this.weight=weight; }        Horse.prototype = new Mammal(); //这里不能用= Mammal,因为Mammal是函数构造器, new Mammal()的通过构造器弄出来的对象var horse = new Horse(10, 20,30);horse.eat();// horse.width = 30;

最后输出的是Horseis eating something.

 

要判断 horse是不是Animal的继承对象,用instanceof 语句来判断

horse instanceof Animal //返回true


有几点:

1. 如果纯粹用原型链的方式, 构造函数的参数是不能传递到原型的构造函数的,可以通过call方法来调用原型的构造函数

2. 指定原型时,Horse.prototype = new Mammal(); 不是指定构造函数Horse.prototype= Mammal; 而是要指向Mammal的对象,不是构造函数对象。

3.  Typeof 运算符在运算引用类型时,无论是什么类型的对象,都返回object, 而instanceof需要明确指出对象特定的类型,所以可以用来判断是否是继承的对象

 

好了, 小结到这里,希望会对以后进一步理解JS 的高级应用有所帮助。

 

主要学习参考来源:

  • W3schools- 一直是Web最好的学习地方
  • http://www.ibm.com/developerworks/cn/web/1304_zengyz_jsoo/index.html?ca=drs  - IBM这位同学总结得很深刻

 

0 0
原创粉丝点击