对象的原型理解

38 阅读2分钟

对象的原型理解

  1. 隐式原型
// 我们每个对象中都有一个属性 [[prototype]], 这个属性可以称之为对象的原型(隐式原型)

var obj = { name: "why" } // 隐藏了属性[[prototype]],指向空对象
var info = {} // [[prototype]]

// 1.解释原型的概念和如何查看原型
// 早期的ECMA是没有规范如何去查看 [[prototype]]

// 给对象中提供了一个属性, 可以让我们查看一下这个原型对象(浏览器提供)
// __proto__
console.log(obj.__proto__) // [object: null prototype] {}
console.log(info.__proto__) // [object: null prototype] {}
// 看似是空对象但并不为空,是因为可枚举属性设置为了false

// var obj = {name: "why", __proto__: {} } 

// // ES5之后提供的Object.getPrototypeOf
console.log(Object.getPrototypeOf(obj)) // {}

// 2.原型有什么用呢?
// 当我们从一个对象中获取某一个属性时, 它会触发 [[get]] 操作
// 1. 在当前对象中去查找对应的属性, 如果找到就直接使用
// 2. 如果没有找到, 那么会沿着它的原型去查找 [[prototype]]
// obj.age = 18 
obj.__proto__.age = 18 // 给原型添加属性age

console.log(obj.age) // 本身对象没有age属性但仍能打印18,沿着原型查找
  1. 函数的原型
function Person() {
}

// 函数也是一个对象
console.log(Person.__proto__) // {} 函数作为对象来说, 它也是有 [[prototype]] 隐式原型

// 函数它因为是一个函数, 所以它还会多出来一个显式原型属性: prototype
console.log(Person.prototype) // {}

// new关键字在调用时会进行的步骤
// 1.在内存中创建一个新的对象(空对象);
// 2.这个对象内部的[[prototype]]属性会被赋值为该构造函数的prototype属性;
// 那么也就意味着我们通过Person构造函数创建出来的所有对象的[[prototype]]属性都指向Person.prototype

var p1 = new Person()
var p2 = new Person()

console.log(p1.__proto__ === Person.prototype) // true
console.log(p2.__proto__ === Person.prototype) // true

// p1.name = "why"
// p1.__proto__.name = "curry"
// Person.prototype.name = "james"
console.log(p1.name)

image.png

image.png

function foo() {

}

// 1.constructor属性
// foo.prototype这个对象中本身有一个constructor属性
console.log(foo.prototype) // {}
console.log(Object.getOwnPropertyDescriptors(foo.prototype)) // {constructor: {…}}

// Object.defineProperty(foo.prototype, "constructor", {
//   enumerable: true,
//   configurable: true,
//   writable: true,
//   value: "哈哈哈哈"
// })

// console.log(foo.prototype)

// prototype.constructor = 构造函数本身
console.log(foo.prototype.constructor) // 可获取属性[Function: foo]
console.log(foo.prototype.constructor.name) // foo

image.png

// 2.我们也可以添加自己的属性
foo.prototype.name = "why"
foo.prototype.age = 18
foo.prototype.height = 18
foo.prototype.eating = function() {

}

var f1 = new foo()
console.log(f1.name, f1.age)

// 当我们要添加的属性有很多时,就会重复foo.prototype
// 3.直接修改整个prototype对象
foo.prototype = {
  // 自己创建的对象没有constructor属性,要加上,指向函数本身(但这种方式添加,可枚举属性默认为true)
  // constructor: foo,
  name: "why",
  age: 18,
  height: 1.88
}

var f1 = new foo()

console.log(f1.name, f1.age, f1.height) // why 18 1.88

// 真实开发中我们可以通过Object.defineProperty方式添加constructor
Object.defineProperty(foo.prototype, "constructor", {
  enumerable: false,
  configurable: true,
  writable: true,
  value: foo
})

image.png

原型和构造函数

// function Person(name, age) {
// 	Person.prototype.name = name,
// 	Person.prototype.age = age
// } //错误

function Person(name, age, height, address) {
  this.name = name
  this.age = age
  this.height = height
  this.address = address
}

Person.prototype.eating = function() {
  console.log(this.name + "在吃东西~")
}

Person.prototype.running = function() {
  console.log(this.name + "在跑步~")
}

var p1 = new Person("why", 18, 1.88, "北京市")
var p2 = new Person("kobe", 20, 1.98, "洛杉矶市")

p1.eating() // why在吃东西~
p2.eating() // kobe在吃东西~