创建对象
1.简单方式
const person = new Object()
person.name = 'Jack'
person.age = 18
person.sayName = function () {
console.log(this.name)
}
2.字面量
const person = {
name: 'Jack',
age: 18,
sayName: function () {
console.log(this.name)
}
}
3.工厂函数
function createPerson (name, age) {
return {
name: name,
age: age,
sayName: function () {
console.log(this.name)
}
}
}
let p1 = createPerson('Jack', 18)
let p2 = createPerson('Mike', 18)
4.构造函数
function Person (name, age) {
this.name = name
this.age = age
this.sayName = function () {
console.log(this.name)
}
}
let p1 = new Person('Jack', 18)
p1.sayName() // => Jack
let p2 = new Person('Mike', 23)
p2.sayName() // => Mike
-
构造函数是根据具体的事物抽象出来的抽象模板
-
实例对象是根据抽象的构造函数模板得到的具体实例对象
-
每一个实例对象都具有一个
constructor
属性,指向创建该实例的构造函 -
可以通过实例的
constructor
属性判断实例和构造函数之间的关系
原型
javascript规定,每一个构造函数都有一个prototype属性,指向另一个对象;这个对象的所有属性和方法,都会被构造函数的实例继承;意味着,可以把所有对象实例需要共享的属性和方法直接定义在prototype对象上
function Person (name, age) {
this.name = name
this.age = age
}
Person.prototype.type = 'human'
Person.prototype.sayName = function () {
console.log(this.name)
}
let p1 = new Person(...)
let p2 = new Person(...)
console.log(p1.sayName === p2.sayName) // => true
这时所有的实例的type属性和sayName()方法,其实都是同一个内存地址,指向prototype对象,因此就提高了运行效率
构造函数、实例、原型之间的关系
1.任何函数都具有一个prototype属性,该属性是一个对象
2.构造函数的prototype对象默认都有一个constructor属性,指向prototype对象所在函数
function F(){} F.contructor === F
3.通过构造函数得到的实例对象内部会包含一个指向构造函数的prototype对象的指针__proto__
var instance = new F()
instance.__proto__ === F.prototype
__proto__是非标准属性
4.实例对象可以直接访问原型对象成员 所有实例都直接或间接地继承了原型对象的成员
原型链
每当代码读取某个对象的某个属性时,都会执行一次搜索,目标是具有给定名字的属性
1.搜索首先从对象实例本身开始
2.如果在实例中找到了具有给定名字的属性,则返回该属性的值
3.如果没有找到,则继续搜索指针指向的原型对象,在原型对象中查找具有给定名字的属性
4.如果在原型对象中找到了这个属性,则返回该属性的值
5.如果在原型对象中也没有找到,则返回undefined
原生对象的原型
所有的函数都有prototype属性对象
Object.prototype | Function.prototype | Array.prototype | String.prototype | Number.prototype | Date.prototype
原型对象的问题:共享数组和共享对象
原型对象使用建议:私有成员(一般就是非函数成员)放到构造函数中;共享成员(一般就是函数)放到原型对象中;如果重置了prototype记得修正constructor的指向
prototype和__proto__
prototype 每个函数都有一个prototype属性,该属性是一个指针,指向一个对象,这个对象包含所有实例共享的属性和方法;原型对象都有一个constructor属性,这个属性指向所关联的构造函数;使用这个对象的好处就是可以让所有实例对象共享它所拥有的属性和方法;这个属性只有js中的类才会有
__proto__ 每个实例对象都有一个proto属性,用于指向构造函数的原型对象;__proto__属性是在调用构造函数创建实例对象时产生的;该属性存在于实例和构造函数的原型对象之间,而不是存在于实例与构造函数之间
原型相关方法
----isPrototypeOf()
判断某个对象是否是某某的原型
例如:Person.prototype.isPrototypeOf(person1)
----Object.getPrototypeOf()
获取原型对象
例如:Object.getPrototypeOf(person1) == Person.prototype
注意:虽然可以通过对象实例访问保存在原型中的值,但却不能通过对象实例重写原型中的值;如果在实例中添加了一个属性,而该属性与实例原型中的一个属性同名,那么就是在实例中创建了这个属性,这个属性将会屏蔽原型中的那个属性
----hasOwnProperty()
判断某个属性是存在与原型中还是存在于实例 存在于实例对象中返回true,否则返回false
console.log(person1.hasOwnProperty("name"))
----in 操作符
无论一个属性存在于实例中还是原型中,只要存在对象中,都会返回true
console.log("name" in person1)
总结:
1.每一个对象都有__proto__属性,__proto__指向Object.prototype(Object构造函数的原型对象)
2.每个函数都有__proto__和prototype属性
3.每个原型对象都有constructor和__proto__属性,其中constructor指回构造函数,而__proto__指向Object.prototype
4.object是所有对象的组先,所有对象都可以通过__proto__属性找到它
5.Function是所有函数的组先,所有的函数都可以通过__proto__属性找到它
6.每个函数都有一个prototype,prototype是一个对象,指向了构造函数的原型对象
7.对象的__proto__属性指向原型,__proto__将对象和原型链接起来组成了原型链