Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

利用 JavaScript 模拟类 #16

Open
yyzclyang opened this issue Aug 13, 2018 · 0 comments
Open

利用 JavaScript 模拟类 #16

yyzclyang opened this issue Aug 13, 2018 · 0 comments

Comments

@yyzclyang
Copy link
Owner

JavaScript中其实是没有类(class)的,但是可以通过一些方法模拟一个“类”出来。

使构造函数

这种方法是利用构造函数模拟一个“类”。

在生成实例的时候,用new就可以。

function Dog(option){
  this.name = option.name;
  this.color = option.color;
  this.run = function(){
    console.log('run')
  }
}

let dog1 = new Dog({
  name: '阿黄',
  color: 'yellow'
})

let dog2 = new Dog({
  name: '小毛',
  color: 'white'
})

这样写有一个弊端,那就是生成的每一个实例对象,都有一个一模一样的run属性和方法,消耗内存。不环保也不效率。

Javascript规定,每一个构造函数都有一个prototype属性,指向另一个对象。这个对象的所有属性和方法,都会被构造函数的实例继承。那么我们可以将相同的属性和方法写在prototype对象上。

function Dog(option){
  this.name = option.name;
  this.color = option.color;
}
Dog.prototype.run = function(){
  console.log('run')
}

let dog1 = new Dog({
  name: '阿黄',
  color: 'yellow'
})

let dog2 = new Dog({
  name: '小毛',
  color: 'white'
})

所有生成的实例对象相同的属性和方法都指向prototype对象,不用重新开辟内存去存放,提高了效率。

Object.create()法

利用Object.create()生成对象实例。

let Dog = {
  run: function () {
    console.log('run')
  }
}

let dog1=Object.create(Dog)

let dog2=Object.create(Dog)

那么它与第一个方法的new有什么区别呢?先来看看Object.create()是怎么实现的。

Object.create = function (o) {       
  function F() {}        
  F.prototype = o;      
  return new F();    
};

可以看出来。Object.create()是内部定义一个对象,并且让F.prototype对象 赋值为引进的对象/函数o,并return出一个新的对象。

从上面的代码和图片中可以看到,这种方法有个弊端,就是只能定义共有属性和方法,无法定义私有属性和方法。

如果要定义私有属性和方法就要另外写。

let Dog = {
  run: function () {
    console.log('run')
  }
}

let dog1 = Object.create(Dog)

let dog2 = Object.create(Dog)

dog1.name = '阿黄'
dog1.color = 'yellow'

dog2.name = '小毛'
dog2.color = 'white'

极简主义法

这个方法是由荷兰程序员Gabor de Mooij提出来的。

它也是用一个对象模拟"类"。在这个类里面,定义一个构造函数createNew(),用来生成实例。然后,在createNew()里面,定义一个实例对象,将私有属性和方法直接写在实例对象上面,将共有属性和方法写在实例对象的__proto__上面,避免共有属性的重复定义,浪费内训。最后把这个实例对象作为返回值。使用的时候,调用createNew()方法,就可以得到实例对象。

var Dog = {    
  createNew: function (option) {      
    var dog = {};      
    dog.name = option.name;
    dog.color = option.color;     
    dog.__proto__.run = function () {
      console.log('run')
    };      
    return dog;    
  }  
};
dog1 = Dog.createNew({
  name: "阿黄",
  color: 'yellow'
})
dog2 = Dog.createNew({
  name: '小毛',
  color: 'white'
})

效果如下:

继承

让一个类继承另一个类,实现起来很方便。只要在前者的createNew()方法中,调用后者的createNew()方法即可。

这就可以将共有属性放在另一个类中,用构造类去继承它即可。

var Animal = {    
  createNew: function () {      
    var animal = {};  
    animal.__proto__.type = 'animal';    
    animal.__proto__.run = function () {
      console.log('run')
    };      
    return animal;    
  }  
};  
var Dog = {    
  createNew: function (option) {      
    var dog = Animal.createNew();    
    dog.name = option.name;
    dog.color = option.color;       
    return dog;    
  }  
};
dog1 = Dog.createNew({
  name: "阿黄",
  color: 'yellow'
})
dog2 = Dog.createNew({
  name: '小毛',
  color: 'white'
})

效果如下:

隐藏属性和方法

在createNew()方法中,只要不是定义在dog对象上的方法和属性,都是隐藏的。

隐藏的属性和方法dog无法直接读取,只能通过dog对象的方法来读取。

var Dog = {    
  createNew: function (option) {      
    var dog = {};  
    dog.name = option.name;
    dog.color = option.color;    
    var sound = "汪汪汪";
    dog.__proto__.makeSound = function () {
      console.log(sound);
    };      
    return dog;    
  }  
};
dog1 = Dog.createNew({
  name: "阿黄",
  color: 'yellow'
})

效果如下:

数据共享

有时候,我们需要所有实例对象,能够读写同一项内部数据。这个时候,只要把这个内部数据,封装在类对象的里面、createNew()方法的外面即可。

当由多个实例对象,其中一个实例对象修改了共享数据时,其他的实例对象也会受到影响。

var Dog = {
  foodAmount: 50,
  createNew: function(option) {
    var dog = {};
    dog.name = option.name;
    dog.color = option.color;
    dog.__proto__.foodNumber = function() {
      console.log(Dog.foodAmount);
    };
    dog.__proto__.eat = function(n) {
      if (n >= 0) {
        Dog.foodAmount -= n;
      } else {
        console.log("数量错误");
      }
    };
    return dog;
  }
};
dog1 = Dog.createNew({
  name: "阿黄",
  color: "yellow"
});
dog2 = Dog.createNew({
  name: "小毛",
  color: "white"
});

效果如下:

并且此时再生成实例对象,不会刷新共享属性,而是继承之前已经更改的共享属性。

dog3 = Dog.createNew({
  name: "小黑",
  color: "black"
});

效果如下:

本笔记学习自Javascript定义类(class)的三种方法你不知道的javascript之Object.create 和new区别

@yyzclyang yyzclyang changed the title 2018.07.03 利用 JavaScript 模拟类 利用 JavaScript 模拟类 Aug 13, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant