对象的原型理解
- 隐式原型
// 我们每个对象中都有一个属性 [[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,沿着原型查找
- 函数的原型
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)
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
// 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
})
原型和构造函数
// 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在吃东西~