【JavaScript】——“重学前端”03对象——JavaScript需要模拟面向对象吗

JavaScript 本身就是面向对象的,这些“模拟面向对象”,实际上做的事情就是“模拟
基于类的面向对象
”。

JavaScript 创始人 Brendan Eich 在“原型运行时”的基础上引入了 new、this 等语言特性,使之“看起来语法更像 Java”,而 Java 正是基于类的面向对象的代表语言之一。

在不同的编程语言中,设计者也利用各种不同的语言特性来抽象描述对象
1、最为成功的流派是使用“”的方式来描述对象,这诞生了诸如 C++、Java 等流行的编程
语言。这个流派叫做基于类的编程语言

2、还有一种就是基于原型的编程语言,它们利用原型来描述对象。我们的 JavaScript 就是其中代表。

“基于类”的编程: 

“基于类”的编程提倡使用一个关注分类和类之间关系开发模型。在这类语言中,总是先有
,再从类去实例化一个对象类与类之间又可能会形成继承、组合等关系。类又往往与语
言的类型系统整合,形成一定编译时的能力。

“基于原型”的编程:

“基于原型”的编程看起来更为提倡程序员去关注一系列对象实例的行为,而后才去关心如何将这些对象,划分到最近的使用方式相似的原型对象,而不是将它们分成类。

基于原型的面向对象系统通过“复制”的方式来创建新对象

一些语言的实现中,还允许复制一个空对象。这实际上就是创建一个全新的对象。

原型系统的“复制操作”有两种实现思路:

        1、一个是并不真的去复制一个原型对象,而是使得新对象持有一个原型的引用
        2、另一个是切实地复制对象,从此两个对象再无关联。
历史上的基于原型语言因此产生了两个流派,显然,JavaScript 显然选择了前一种方式。


JavaScript 的原型:

原型系统可以说相当简单,我可以用两条概括:
        1、如果所有对象都有私有字段 [[prototype]],就是对象的原型;
        2、读一个属性,如果对象本身没有,则会继续访问对象的原型,直到原型为空或者找到为止。

从 ES6 以来,JavaScript 提供了一系列内置函数,以便更为直接地访问操纵原型。三个方法分别为:
        Object.create 根据指定的原型创建新对象,原型可以是 null;
        Object.getPrototypeOf 获得一个对象的原型;
        Object.setPrototypeOf 设置一个对象的原型。

//下面的代码展示了用原型来抽象猫和虎的例子。

//创建一个“猫”对象
var cat = {
     say(){
         console.log("meow~");
     },
     jump(){
         console.log("jump");
     }
}
//根据猫做了一些修改创建了虎
var tiger = Object.create(cat, {
     say:{
         writable:true,
         configurable:true,
         enumerable:true,
         value:function(){
             console.log("roar!");
         }
     }
})

//可以用Object.create 来创建另外的猫和虎对象
//我们可以通过“原始猫对象”和“原始虎对象”来控制所有猫和虎的行为。
var anotherCat = Object.create(cat);

anotherCat.say();

var anotherTiger = Object.create(tiger);

anotherTiger.say();

new操作具体做了哪些事情:

new 运算接受一个构造器和一组调用参数,实际上做了几件事:
        1、以构造器的 prototype 属性(注意与私有字段 [[prototype]] 的区分)为原型,创建新
对象;
        2、将 this 和调用参数传给构造器,执行;
        3、如果构造器返回的是对象,则返回,否则返回第一步创建的对象。

new 这样的行为,它客观上提供了两种方式,

        一是在构造器中添加属性

        二是在构造器的 prototype 属性上添加属性

下面代码展示了用构造器模拟类的两种方法:

//第一种方法是直接在构造器中修改 this,给 this 添加属性。
function c1(){
     this.p1 = 1;
     this.p2 = function(){
         console.log(this.p1);
     }
} 
var o1 = new c1;
o1.p2();


//第二种方法是修改构造器的 prototype 属性指向的对象
//它是从这个构造器构造出来的所有对象的原型。
function c2(){
}
c2.prototype.p1 = 1;
c2.prototype.p2 = function(){
     console.log(this.p1);
}

var o2 = new c2;
o2.p2();

ES6 中的类——class:

类的基本写法:

class Rectangle {
     constructor(height, width) {
         this.height = height;
         this.width = width;
     }
     // Getter
     get area() {
         return this.calcArea();
     }
     // Method
     calcArea() {
         return this.height * this.width;
     }
}

我们通过 get/set 关键字来创建 getter,通过括号和大括号来创建方法,数据型成员最好
写在构造器里面。

类提供了继承能力。

//创造了 Animal 类
class Animal {
     constructor(name) {
         this.name = name;
     }
     speak() {
         console.log(this.name + ' makes a noise.');
     }
}

//通过 extends 关键字让 Dog 继承 Animal 
class Dog extends Animal {
     constructor(name) {
         super(name); // call the super class constructor and pass in the name parameter
     }

     speak() {
         console.log(this.name + ' barks.');
     }
}


//调用子类的 speak 方法获取了父类的 name。
let d = new Dog('Mitzie');
d.speak(); // Mitzie barks.

所以当我们使用类的思想来设计代码时,应该尽量使用 class 来声明类,而不是用旧语法,
拿函数来模拟对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值