一次性解决javascript的prototype、__proto__、constructor
继承与原型链
作为一名前端工程师,必须搞懂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 ---> nullvar a = ["yo", "whadup", "?"];
// 数组都继承于 Array.prototype
// (Array.prototype 中包含 indexOf, forEach 等方法)
// 原型链如下:
// a ---> Array.prototype ---> Object.prototype ---> nullfunction 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,该传入对象的自有可枚举属性(即其自身定义的属性,而不是其原型链上的枚举属性)将为新创建的对象添加指定的属性值和对应的属性描述符。
var a = {a: 1};
// a ---> Object.prototype ---> nullvar b = Object.create(a);
// b ---> a ---> Object.prototype ---> null
console.log(b.a);
// 1 (继承而来)var c = Object.create(b);
// c ---> b ---> a ---> Object.prototype ---> nullvar d = Object.create(null);
// d ---> null
console.log(d.hasOwnProperty);
// undefined, 因为d没有继承Object.prototype
4、使用class关键字创建对象
ECMAScript6 引入了一套新的关键字用来实现
class
。使用基于类语言的开发人员会对这些结构感到熟悉,但它们是不同的。JavaScript 仍然基于原型。这些新的关键字包括 class
, constructor
,static
,extends
和 super
。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)// 4square.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() 【一次性解决javascript的prototype、__proto__、constructor】
Object.getPrototypeOf()
方法返回指定对象的原型(内部[[Prototype]]
属性的值,也就是__proto__
)。var proto = {};
var obj = Object.create(proto);
Object.getPrototypeOf(obj) === proto;
// truevar reg = /a/;
Object.getPrototypeOf(reg) === RegExp.prototype;
// true
推荐阅读
- parallels|parallels desktop 解决网络初始化失败问题
- 考研英语阅读终极解决方案——阅读理解如何巧拿高分
- MybatisPlus|MybatisPlus LambdaQueryWrapper使用int默认值的坑及解决
- 事件代理
- SpringBoot调用公共模块的自定义注解失效的解决
- 解决SpringBoot引用别的模块无法注入的问题
- 数组常用方法一
- Spark|Spark 数据倾斜及其解决方案
- 解决SyntaxError:|解决SyntaxError: invalid syntax
- Spectrum|Spectrum 区块偶尔停止同步问题排查与解决笔记