面向对象的基本概念:类和实例。JavaScript不区分类和实例,通过原型来实现面向对象。

1. 类--->原型对象

JavaScript是一种直译式脚本语言,是一种动态类型、弱类型、基于原型的语言,内置支持类型。这种动态语言,是指程序在运行时可以改变其结构:新的函数可以被引进,已有的函数可以被删除等在结构上的变化。

本身不提供class实现(在ES2015/ES6中引入class关键字,但只是语法糖,JavaScript仍然是基于原型的)。

首先,我知道:

  人——小红

  动物——狗

  ....

类就是对象的类型模板,它集合了所有共性,是抽象出来的。那么我们怎么来创建一个具体的对象呢?这有一个过程:

(1)基于{...}对象

var people= {
    name: '小红',
    height: 1.6,
    run: function () {
        console.log(this.name + ' is running...');
    }
}

这里我定义了一个叫小红的人,她有名、身高和跑步的特性。这些特性是人都有吧。我们可以继承她的特性,前面讲过js是通过原型来实现面向对象。

所以,基于people,我们要创建一个叫小强的人:

  var xiaoqiang= {

    name: '小强'

  }

  xiaoqiang.__proto__=people;(实际上,不要用obj.__proto__改变一个对象的原型,低版本IE也无法使用__proto__ )

把xiaoqiang的原型指向了对象people,根据原型链的思路,xiaoqiang.height和xiaoqiang.run在xiaoqiang里找不到,找上层原型,所以实现了一种“继承”。

JavaScript没有class的概念。所有对象都是实例。继承关系即一个对象的原型指向另一个对象。

 

(2)Object.create()

这个方法可以传入一个原型对象,并创建一个基于该原型的新对象。以上可封装函数为:

function createPeople(name){
  //基于people 创建一个具体的人对象 
  var p = Object.create(people);    
  //并通过传入的值更新为这个人的具体特性
  p.name = name;  
  return p;
}

var xiaoqiang=createPeople('小强')
xiaoqiang.__proto__===people //同理

 

(3)构造函数

JavaScript对每个创建的对象都会设置一个原型,指向它的原型对象。

这里,先好好说说原型链

  当我们用obj.xxx访问一个对象的属性时,JavaScript引擎先在当前对象上查找该属性,如果没有找到,就到其原型对象上找,如果还没有找到,就一直上溯到Object.prototype对象,最后,如果还没有找到,就只能返回undefined。

  如:

    arr——>Array.prototype——>Object.prototype——>null

    或是自定义函数func,Function.prototype定义了apply()方法,所以所有函数都可以调用apply()方法

    func——>Function.prototype——>Object.prototype——>null

 

前面两种方法创建对象,这里是用一种构造函数的方法创建对象,先定义构造函数

function People(name){
  this.name = name;
  this.run =function () {
    console.log(this.name + ' is running...');
   }
 }

可以看出这就是一个普通函数,我其实就是将第一个字母大写而已。

new People(),它就是构造函数,所绑定的this指向新创建的对象,默认返回this;不写new,是普通函数,返回undefined。

var xiaoqiang = new People('小强');

好了,把小强创造出来了!(o゚▽゚)o  

  同样,我们看看它的原型链:

  xiaoqiang——>People.prototype——>Object.prototype——>null

 

constructor

  原型链上的都有一个constructor属性,指向构造函数。

  xiaoqiang.constructor === People.prototype.constructor; // true

  People.prototype.constructor === People; // true

  Object.getPrototypeOf(xiaoqiang) === People.prototype; // true

  xiaoqiang instanceof People; // true

People有属性prototype指向xiaoqiang的原型对象。xiaoqiang这个对象是没有prototype属性的。

前面讲到继承关系即一个对象的原型指向另一个对象。所以如图:

JavaScript面向对象的优点 javascript 面向对象_JavaScript面向对象的优点

 

 

改进方法:

  前面run这个方法,写在构造函数里面的。new创建多个对象,多个对象都有自己的一个run函数,这里要做到的是共享同一个函数,即把方法都放到原型上去。

  

People.prototype.run=function(){
  console.log(this.name + ' is running...');

}

 

最后,封装了一个实例化对象的函数:

function createPeople(props) {
    return new People(props || {})
}

 

2.继承

传统的class继承应该是扩展一个已有的class,生成新的class。可是JavaScript不存在class类型,是采用原型继承的( ̄. ̄)  ,怎么办呢?

办法是,基于People扩展出PrimaryPeople,那么定义这个构造函数:

function PrimaryPeople(props){
    People.call(this, props);
    this.age=props.age || 1;
}

这时候原型链是:

  new PrimaryPeople——>PrimaryPeople.prototype——>Object.prototype——>null

  这原型链就不对啊,应该继承People,用个空函数F作桥接,封装为:

function inherits(Child, Parent) {
    var F = function () {};
    F.prototype = Parent.prototype;
    Child.prototype = new F();
    Child.prototype.constructor = Child;
}

 

3. class

以上的继承蛮费解,在ES6开始引入了关键字class到JavaScript中!

编写类这样写:

class People{
    constructor(name){
        this.name = name;
    } 
    
    run(){
       console.log(this.name + ' is running...');
    } 
}

创建是同样的

  var xiaoqiang=new People('小强');

而继承直接通过extends实现:

class PrimaryPeople{
    constructor(name, age){
        //用super调用父类的构造方法
        super(name);
        this.age = age;
    } 
    
    newfunc(){
      
    } 
}

若是不支持ES6的class,使用工具Babel将class代码转换为传统的prototype代码