关于javascript:一次性解决javascript的prototypeprotoconstructor

9次阅读

共计 3768 个字符,预计需要花费 10 分钟才能阅读完成。

继承与原型链

作为一名前端工程师,必须搞懂 JavaScript 中的 prototype__proto__constructor
绝对于基于类的语言,尽管 JavaScript 是动静的,但自身不提供一个 class 的实现。即使是在 ES6 中引入了 class 关键字,但那也只是语法糖,JavaScript 依然是基于原型的。
当谈到继承的时候,JavaScript 只有一种构造:对象,每个实例对象都有一个公有属性 __proto__ 指向他的构造函数的原型对象prototype

  • __proto__constructor 是对象才有的属性
  • prototype 是函数才有的属性
  • JavaScript 中函数也是对象,所以函数岂但领有 prototype,还有 __proto__constructor 属性
function Func () {return 1}
let f1 = new Func()
let f2 = new Func()

以上代码,f1 和 f2 都是 Func 的实例。
所以,函数对象和实例对象各自的属性:
Func 领有以下属性:prototype__proto__constructor
f1 和 f2 领有一下属性:__proto__constructor,其中 constructor 是继承来的

继承属性

JavaScript 对象是动静的属性“包”(指其本人的属性)。JavaScript 对象有一个指向一个原型对象的链。当试图拜访一个对象的属性时,它不仅仅在该对象上搜查,还会搜查该对象的原型,以及该对象的原型的原型,顺次层层向上搜寻,直到找到一个名字匹配的属性或达到原型链的开端。

继承办法

JavaScript 并没有其余基于类的语言所定义的“办法”。在 JavaScript 里,任何函数都能够增加到对象上作为对象的属性。函数的继承与其余的属性继承没有差异,包含下面的“属性遮蔽”(这种状况相当于其余语言的办法重写)。
当继承的函数被调用时,this 指向的是以后继承的对象,而不是继承的函数所在的原型对象。

创建对象和生成原型链的形式

1、应用语法结构创建对象

var o = {a: 1};
// o 这个对象继承了 Object.prototype 下面的所有属性
// o 本身没有名为 hasOwnProperty 的属性
// hasOwnProperty 是 Object.prototype 的属性
// 因而 o 继承了 Object.prototype 的 hasOwnProperty
// Object.prototype 的原型为 null
// 原型链如下:
// o ---> Object.prototype ---> null

var a = ["yo", "whadup", "?"];
// 数组都继承于 Array.prototype
// (Array.prototype 中蕴含 indexOf, forEach 等办法)
// 原型链如下:
// a ---> Array.prototype ---> Object.prototype ---> null

function f(){return 2;}
// 函数都继承于 Function.prototype
// (Function.prototype 中蕴含 call, bind 等办法)
// 原型链如下:
// f ---> Function.prototype ---> Object.prototype ---> null

2、应用结构器创建对象

在 JavaScript 中,结构器其实就是一个一般的函数。当应用 new 操作符 来作用这个函数时,它就能够被称为构造方法(构造函数)。

function Graph() {this.vertices = [];
  this.edges = [];}

Graph.prototype = {addVertex: function(v){this.vertices.push(v);
  }
};

var g = new Graph();
// g 是生成的对象,他的本身属性有 'vertices' 和 'edges'。// 在 g 被实例化时,g.[[Prototype]] 指向了 Graph.prototype。// 所以调用 g.addVertex(1)的时候,就是调用了 Graph.prototype.addVertex(1)

3、应用 Object.create 创建对象

ECMAScript 5 中引入了一个新办法:Object.create(),办法创立一个新对象,应用现有的对象来提供新创建的对象的 __proto__
语法:

  • Object.create(proto,[propertiesObject])

参数:

  • proto

    • 新创建对象的原型对象。
  • propertiesObject

    • 可选参数,须要传入一个对象,如果该参数被指定且不为 undefined,该传入对象的自有可枚举属性 (即其本身定义的属性,而不是其原型链上的枚举属性) 将为新创建的对象增加指定的属性值和对应的属性描述符。

能够调用这个办法来创立一个新对象。新对象的原型就是调用 create 办法时传入的第一个参数:

var a = {a: 1};
// a ---> Object.prototype ---> null

var b = Object.create(a);
// b ---> a ---> Object.prototype ---> null
console.log(b.a); // 1 (继承而来)

var c = Object.create(b);
// c ---> b ---> a ---> Object.prototype ---> null

var d = Object.create(null);
// d ---> null
console.log(d.hasOwnProperty); // undefined, 因为 d 没有继承 Object.prototype

4、应用 class 关键字创建对象

ECMAScript6 引入了一套新的关键字用来实现 class。应用基于类语言的开发人员会对这些构造感到相熟,但它们是不同的。JavaScript 依然基于原型。这些新的关键字包含 class, constructorstaticextendssuper

class Polygon {constructor(heigth, width) {
    this.heigth = heigth;
    this.width = width;
  }
}

class Square extends Polygon {constructor(sideLength) {super(sideLength, sideLength)
  }
  get area () {return this.heigth * this.width}
  set sideLength (newLength) {
    this.heigth = newLength;
    this.width = newLength;
  }
}

var square = new Square(2)
// console.log(square.area)  // 4

square.sideLength = 8
console.log(square.area)  // 64

性能

在原型链上查找属性比拟耗时,对性能有副作用,这在性能要求刻薄的状况下很重要。另外,试图拜访不存在的属性时会遍历整个原型链。
遍历对象的属性时,原型链上的每个可枚举属性都会被枚举进去。要查看对象是否具备本人定义的属性,而不是其原型链上的某个属性,则必须应用所有对象从 Object.prototype 继承的 hasOwnProperty 办法,办法会返回一个布尔值,批示对象本身属性中是否具备指定的属性。

function Graph () {this.vertices = [];
  this.edges = [];}

Graph.prototype = {addVertex: function (v) {this.vertices.push(v);
  }
};

var g = new Graph();
// g 是生成的对象,他的本身属性有 'vertices' 和 'edges'。// 在 g 被实例化时,g.[[Prototype]] 指向了 Graph.prototype。// 所以调用 g.addVertex(1)的时候,就是调用了 Graph.prototype.addVertex(1)

console.log(g.hasOwnProperty('vertices'))     // true
console.log(g.hasOwnProperty('nope'))                // false
console.log(g.hasOwnProperty('addVertex'))    // false
console.log(g.__proto__.hasOwnProperty('addVertex'))    // true
console.log(g.__proto__.hasOwnProperty('addvertex'))    // false, 辨别大小写

prototype 和 getPrototypeOf()

Object.getPrototypeOf() 办法返回指定对象的原型(外部 [[Prototype]] 属性的值,也就是__proto__)。

var proto = {};
var obj = Object.create(proto);
Object.getPrototypeOf(obj) === proto; // true

var reg = /a/;
Object.getPrototypeOf(reg) === RegExp.prototype; // true
正文完
 0