javascript之原型

267 阅读3分钟

winter老师《重学前端》学习笔记

什么是原型?

在不同的编程语言中,设计者也利用各种不同的语言特性来抽象描述对象,如

  • 1、利用类的方式描述对象,如java、c++,基于类的编程语言
  • 2、利用原型来描述对象,如js、self、kevo,基于原型的编程语言

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

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

基于原型和基于类都能够满足基本的复用和抽象需求,但是适用的场景不太相同

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

  • 一个是并不真的去复制一个原型对象,而是使得新对象持有一个原型的引用;
  • 另一个是切实地复制对象,从此两个对象再无关联。

历史上的基于原型语言因此产生了两个流派,显然,JavaScript 显然选择了前一种方式

js的原型

原型系统的概述:

  • 1、所有对象都有原型,存放在私有字段[[prototype]]
  • 2、读取一个属性,如果对象本身没有,则会继续访问对象的原型,直到原型为空或者找到为止

js中提供可以直接的访问操纵原型,

  • Object.create 根据指定的原型创建新对象,原型可以是null
  • Object.getPrototypeOf获得一个对象的原型
  • Object.setPrototypeOf设置一个对象的原型
var Cat = {
    say: function(){
        console.log('miao~');
    },
    jump: function(){
        console.log('jump')
    }
}

var Tiger = Object.create(Cat, {
    say: {
        writable: true,
        configurable: true,
        enumerable: true,
        value: function(){
            console.log('mao~')
        }
    }
})

var cat = Object.create(Cat);
cat.say();

var tiger = Object.create(Tiger);
tiger.say();

早期版本中的类与原型

语言使用者唯一可以访问[[class]]属性的方式是 Object.prototype.toString

在 ES3 和之前的版本,JS 中类的概念是相当弱的,它仅仅是运行时的一个字符串属性。

在 ES5 开始,[[class]] 私有属性被 Symbol.toStringTag 代替,Object.prototype.toString 的意义从命名上不再跟 class 相关

var obj = {[Symbol.toStringTag]: 'MyObject'};
console.log(o + '')

//[object MyObject]

new运算符接受一个构造器和一组调用参数,实际上做了几件事

  • 以构造函数的prototype属性(区别于私有字段[[prototype]])为原型,创建一个新对象
  • 将this和调用参数传递给构造函数,执行
  • 如果构造函数返回对象,则返回,否则返回第一步创建的对象

new的行为,试图让函数对象在语法上变得跟类相似:

  • 一是在构造器中添加属性,
  • 二是在构造器的 prototype 属性上添加属性
function Foo(){
	this.f1 = 1;
    this.f2 = function(){
    	console.log(this.f1);
    }
}

function Bar(){}
Bar.prototype.f1 = 1;
Bar.prototype.f2 = function(){
	console.log(this.f1);
}

第一种方法是直接在构造器中修改 this,给 this 添加属性。

第二种方法是修改构造器的 prototype 属性指向的对象,它是从这个构造器构造出来的所有对象的原型

ES6中的类

ES6中加入新特性class,基于类的编程方式成为了js的官方编程范式

class Foo{
	constructor(f){
    	this.f1 = f;
    }
    f2(){
    	console.log(this.f1);
    }
}

类的写法实际上也是由原型运行时来承载的,逻辑上 JavaScript 认为每个类是有共同原型的一组对象,数据属性写在对象上,访问器属性和方法写在原型对象之上