JavaScript - 原型与原型链

368 阅读3分钟

1、核心概念

原型:泛指

  • 几乎每个JavaScript对象都有另一个与之相关的对象,这另一个对象被称之为原型。

  • 第一个对象从这个原型继承属性

显式原型: 函数的 prototype 属性

隐式原型: 对象的 __proto__ 属性

原型对象:指具体的对象

  • 函数的prototype属性(或着说对象的__proto__属性)指向的对象称为原型对象

  • 每个对象拥有一个原型对象,对象以其原型为模板、从原型继承方法和属性。

原型链

  • 原型对象也可能拥有原型,并从中继承方法和属性,一层一层、以此类推,这种关系被称为原型链

2、特点

  • 所有构造函数的 __proto__ 属性都指向 Function.prototype
  • 所有普通对象的 __proto__ 属性都指向 Object.prototype
  • Object.prototype.__proto__ === null
  • 构造函数的 prototype 属性指向原型对象
  • 原型对象的 constructor 属性指向构造函数
  • 实例的 __proto__ 属性指向原型对象

3、原型相关操作方法

getPrototypeOf:返回指定对象的原型(内部[[Prototype]]属性的值)
let x = {};
let y = {};
Object.getPrototypeOf(x) == Object.prototype;
Object.getPrototypeOf(y) == Object.prototype;
Object.getPrototypeOf(x) == Object.getPrototypeOf(y)
setPrototypeOf:设置一个指定的对象的原型 ( 即[[Prototype]]属性)到另一个对象或 null
let hd = {};
let parent = { name: "parent" };
Object.setPrototypeOf(hd, parent);//将parent设置为hd的原型
Object.getPrototypeOf(hd)//{ name: "parent" }

Object.create 创建一个新对象时使用现有对象做为新对象的原型对象

//使用Object.create 设置对象原型
let user = {
  show() {
    return this.name;
  }
};
let hd = Object.create(user);
hd.name = "小马哥";
console.log(hd.show());//小马哥
//第二个参数设置新对象的属性
let user = {
  show() {
    return this.name;
  }
};
let hd = Object.create(user, {
  name: {
    value: "小马哥"
  }
});
console.log(hd.show());//小马哥

instanceof 检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上

function A() {}
function B() {}
function C() {}

const c = new C();
B.prototype = c;
const b = new B();
A.prototype = b;
const a = new A();

console.dir(a instanceof A); //true
console.dir(a instanceof B); //true
console.dir(a instanceof C); //true
console.dir(b instanceof C); //true
console.dir(c instanceof B); //false

属性遍历

使用in 检测原型链上是否存在属性,使用 hasOwnProperty 只检测当前对象
let a = { url: "www.tengxun.com" };
let b = { name: "小马哥" };
Object.setPrototypeOf(a, b);

"name" in a //小马哥
a.hasOwnProperty("name") //false
a.hasOwnProperty("url") //true
使用 for/in 遍历时同时会遍历原型上的属性如下例
let hd = { name: "小马哥" };
let xj = Object.create(hd, {
  url: {
    value: "www.baidu.com",
    enumerable: true
  }
});
for (const key in xj) {
  console.log(key);//name、url
}
hasOwnProperty 方法判断对象是否存在属性,而不会查找原型
let hd = { name: "小马哥" };
let xj = Object.create(hd, {
  url: {
    value: "www.baidu.com",
    enumerable: true
  }
});
for (const key in xj) {
  if (xj.hasOwnProperty(key)) {
    console.log(key);
  }
}

4、构造函数

  • 当一个函数用来创建一类对象时,被称作构造函数;
  • 构造函数内的属性和方法;仅可以由当前实例访问;
  • 构造函数的 prototype 属性指向原型对象
  • 原型对象的 constructor 属性指向构造函数
  • 实例的 __proto__ 属性指向原型对象

new一个对象的过程

1、创建一个新的对象

2、新的对象会被执行[[prototype]]连接

3、新对象和函数调用的this会绑定起来

4、执行函数中的代码

5、如果函数没有返回值,默认返回新创建的对象

function Fun() {
  this.show = function() {
    return "show in object";
  };
}
Fun.prototype.show = function() {
  return "show in prototype";
};
const obj = new Fun();
console.log(obj.show());