1. 对象的原型理解
image.png
// 我们每个对象中都有一个 [[prototype]], 这个属性可以称之为对象的原型(隐式原型)
var obj = { name: "why" } // [[prototype]]
var info = {} // info里面有这个[[prototype]]对象
// 1.解释原型的概念和看一下原型
// 早期的ECMA是没有规范如何去查看 [[prototype]]
// 给对象中提供了一个属性, 可以让我们查看一下这个原型对象(浏览器提供)
// __proto__
// console.log(obj.__proto__) // {}
// console.log(info.__proto__) // {}
// 就像是var obj = {name: "why", __proto__: {} }
// // ES5之后提供的Object.getPrototypeOf
console.log(Object.getPrototypeOf(obj))
console.log(Object.getPrototypeOf(obj) === obj.__proto__)//true
// 2.原型有什么用呢?
// 当我们从一个对象中获取某一个属性时, 它会触发 [[get]] 操作
// 1. 在当前对象中去查找对应的属性, 如果找到就直接使用
// 2. 如果没有找到, 那么会沿着它的原型去查找 [[prototype]]
// obj.age = 18
//obj.__proto__.age = 18
//console.log(obj.age)
2.函数的原型理解(显示原型)
image.pngfunction foo() {
}
// 1.函数也是一个对象
// console.log(foo.__proto__) // 函数作为对象来说, 它也是有[[prototype]] 隐式原型
// 2.函数它因为是一个函数, 所以它还会多出来一个显示原型属性: prototype,而且对象是没有这个属性的,只有函数有
console.log(foo.prototype)
var f1 = new foo()
var f2 = new foo()
console.log(f1.__proto__ === foo.prototype)
console.log(f2.__proto__ === foo.prototype)
new关键字的步骤如下:
1.在内存中创建一个新的对象(空对象);
2.这个对象内部的[[prototype]]属性会被赋值为该构造函数的prototype属性;(后面详细讲);
那么也就意味着我们通过Person构造函数创建出来的所有对象的[[prototype]]属性都指向Person.prototype:
image.png
48.PNG
49.PNG
3.函数原型上的属性
image.pngimage.png
//为啥么呢?因为Person.prototype没有constructor这个属性,就会去Person.prototype.proto 查找,也就是{name: "123",}的.proto ,它指向Object.prototype,Object.prototype的constructor指向Object
function Person(){ }
Person.prototype = {
name:"123"
}
console.log(Person.prototype.constructor)//function Object() { [native code] }
const newObjTest = {}
console.log(newObjTest.__proto__ === Object.prototype)//true
console.log(Person.prototype.constructor === Object)//true
image.png
function foo() {
}
// 1.constructor属性
// foo.prototype这个对象中有一个constructor属性
// console.log(foo.prototype)
// console.log(Object.getOwnPropertyDescriptors(foo.prototype))//可枚举是false
// 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)
// console.log(foo.prototype.constructor.prototype.constructor.prototype.constructor)
// 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)
// 3.直接修改整个prototype对象(适合于给原型添加东西很多的情况)
foo.prototype = {
// constructor: foo,
name: "why",
age: 18,
height: 1.88
}
var f1 = new foo()
console.log(f1.name, f1.age, f1.height)
// 真实开发中我们可以通过Object.defineProperty方式添加constructor
Object.defineProperty(foo.prototype, "constructor", {
enumerable: false,
configurable: true,
writable: true,
value: foo
})
4.创建对象方案-原型和构造函数
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 + "在跑步~")
}
//this是动态绑定的
var p1 = new Person("why", 18, 1.88, "北京市")
var p2 = new Person("kobe", 20, 1.98, "洛杉矶市")
p1.eating()
p2.eating()
50.png
5.原型链
原型对象也是对象,所以它也有原型
当我们使用一个对象的属性或方法时,会先在自身中寻找,
自身中如果有,则直接使用
如果没有则去原型对象中寻找,如果原型对象中有,则使用
如果没有,则去原型的原型中去寻找,直到找到Object对象的原型,再没有的话,就会返回undefined
6.总结
函数有一个prototype属性,它指向原型对象。原型对象里面有一个constructor属性,指向这个函数自己。
通过函数new出来的对象都有一个__proto__
属性,这个属性指向函数的原型对象。
直接通过字面量{}或者new Object出来的对象也是有一个__proto__
属性的,它指向Object函数的原型对象。
函数的原型对象也是一个对象,所以它是有一个__proto__
属性的,指向Object的原型对象。
Object也是一个构造函数。但是它的原型对象是的__proto__
属性是指向null的,这个比较特殊。
网友评论