JavaScript:原型机制实现的面向对象

JavaScript创建对象
  • 直接声明一个对象
var person = {
  name: ['Bob', 'Smith'],
  age: 32,
  gender: 'male',
  interests: ['music', 'skiing'],
  bio: function() {
    alert(this.name[0] + ' ' + this.name[1] + ' is ' + this.age + ' years old. He likes ' + this.interests[0] + ' and ' + this.interests[1] + '.');
  },
  greeting: function() {
    alert('Hi! I\'m ' + this.name[0] + '.');
  }
};
  • 定义并使用构造函数
function Person(first, last, age, gender, interests) {
  this.name = {
    'first': first,
    'last': last
  };
  this.age = age;
  this.gender = gender;
  this.interests = interests;
  this.bio = function() {
	    alert(this.name.first + ' ' + this.name.last + ' is ' + this.age + ' years old.' + str);
  };
  this.greeting = function() {
    alert('Hi! I\'m ' + this.name.first + '.');
  };
};
  • 使用Object()构造函数
    使用Object()函数制造一个对象,为这个对象添加属性和方法
    还可以将对象定义传入Object()中作为参数
var person1 = new Object({
  name : 'Chris',
  age : 38,
  greeting : function() {
    alert('Hi! I\'m ' + this.name + '.');
  }
});
  • 使用create()方法
var person2 = Object.create(person1);

person2是基于person1创建的, person2具有person1的属性和方法


划重点

对象原型

JS实现的面向对象的继承实现与其他OO语言有着本质区别

通过原型这种机制,JavaScript 中的对象从其他对象继承功能特性

在传统的 OOP 中,首先定义“类”,此后创建对象实例时,类中定义的所有属性和方法都被复制到实例中。在 JavaScript 中并不如此复制——而是在对象实例和它的构造器之间建立一个链接(它是__proto__属性,是从构造函数的prototype属性派生的),之后通过上溯原型链,在构造器中找到这些属性和方法。

prototype属性与__proto__属性

也就是说,每个对象都是构造在原型对象之上
构造函数具有prototype属性,所有会被继承的属性都定义在这里
每个对象都有__proto__属性,__proto__属性存放原型对象,新的标准中,__proto__已弃用,由Object.getPrototypeOf(obj)替代,用于得到原型对象

由构造器制造的对象,其_proto_属性指向构造器的prototype对象
是用create()方法由某对象制造的新对象,新对象的__proto__属性为原对象,即create()方法实际做的是从指定原型对象创建一个新的对象
默认情况下, 所有函数的原型属性的__proto__都是 window.Object.prototype

function Person(){};
var person = new Person();
var person1 = Object.create(person);
person.__proto__ === Person.prototype;   true
person1.__proto__ === person;    true;

与Java等OO语言不同原型链中的方法和属性没有被复制到其他对象——它们的访问是通过“原型链”的方式层层索引,类似子类对象调用父类中定义的方法

constructor

每个实例对象都从原型中继承了一个constructor属性,该属性指向了用于构造此实例对象的构造函数。
每一个对象的constructor属性都应当返回构造此实例的构造函数

所以 new instance.constructor(arguments) 即是使用构造函数制造了一个对象

instance.constructor.name 还能得到构造函数的名字


在讲constructor之前可能你就想对prototype做点什么了
没错,说的就是我

  • 在原型上增加方法
Person.prototype.farewell = function() {
  alert(this.name.first + ' has left the building. Bye for now!');
}

那么在这条原型链下游的原型/对象都可以上溯原型链,从而调用到这个方法
即使那些对象是在Person中的prototype属性增加farewell属性之前创建的
这就是原型机制实现的OO的特点

  • 在原型上增加属性
Person.prototype.fullName = 'Bob Smith';

然而这种做法使得fullName是一个属于原型的属性,类似Java中的类变量,因此这种方法可以用来定义常属性(静态属性)


那么如何定义用于继承的属性?
在构造函数中声明属性是恰当的方法

function Person(first, last, age, gender, interests) {
	fullName = this.name.first + ' ' + this.name.last;
};

构造函数中的this是动态绑定的,因此访问到的是当前对象的name

因此一种常见的对象(原型)定义模式是在构造器中定义属性,在prototype属性上定义方法

// 构造器及其属性定义

function Test(a,b,c,d) {
  // 属性定义
  this.a = a;
  ...
};

// 定义第一个方法

Test.prototype.x = function () { ... }

// 定义第二个方法

Test.prototype.y = function () { ... }

// 等等……

2019/5/26

发布了85 篇原创文章 · 获赞 83 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/kafmws/article/details/90339852