本章内容一共分为四大项,然后寻行渐近的说名,这四大项是 【创建对象有几种方法】【原型、构造函数、实例、原型链】【instanceof原理】【new运算符】
一、创建对象的几种方式
第1种:字面量
let n1 = {a: 1}
let n2 = new Object({a: 2})
第2种: 通过构造函数
let M = function(name){ this.name = name } let n3 = new M('a3')
第3种: Object.create创建
let p = {name: 'p'} let n4 = Object.create(p)
二、原型、构造函数、实例、原型链
首先我们来看一张图片
说明:
- 每一个构造函数都有一个显式原型(prototype)
- 每一个构造函数都有一个构造器
- 每一个实例都有一个隐式原型(__proto__)
- 实例的隐式原型(__proto__)指向构造函数的显式原型(prototype)
- 构造函数的显式原型的constructor指向是构造函数
附加:
(1)ES6中的class是函数的语法糖
(2)只有函数才有prototype,对象没有(函数也是对象)
(3)只有实例对象有__proto__,函数也有__proto,因为函数也是对象xx.__proto__ === Function.prototype(返回true,xx代表函数)
(4)任何一个实例对象,通过原型链找到它上面的原型对象,那个上面的方法和属性,都是被实例所共享的(这样子可以避免在每个构造函数上都创建相同的方法,造成代码冗余)。
代码演练:M是构造函数,n3是实例对象
let M = function(name){
this.name = name
}
let n3 = new M('a3')
我们再来看一张图片(哈哈,本人手绘板,有点丑😂):
原型链原理:从一个实例对象往上找这个实例相关联的原型对象,这个原型对象再往上找又有创造它的上一级的原型对象,以此类推,一直找到Object.prototype而终止。下面代码可以说明问题,对应图形见上图。
class Animal{
constructor(name){
this.name = name
}
eat(){
console.log('我爱吃')
}
}
class Dog extends Animal{
constructor(name,age){
super(name)
this.age = age
}
say(){
console.log('我会汪汪叫')
}
}
let dog = new Dog('vip dog', 3)
三、instanceof原理
来来来,咱门再看一张图,嘿嘿,我最喜欢看图说话了!
- instanceof原理:是为了判断此实例或者构造器是否是父级继承的。
- 判断函数Animal是否是实例dog继承的构造函数方法
- dog instanceof Animal === true
原理:dog.__proto__.[ __proto__ ···假设有n个__proto__··· ] === Animal.prototype
缺陷:这个方法不够准确,因为只要是同一条原型链上都是true,所以没法证实dog实例最近的构造函数是哪个
例如:dog.__proto__.__proto__.__proto__ === Animal.prototype === Object.prototype
- 只有constructor才能确定dog实例是哪个最近的构造函数
dog.__proto__.constructor === Dog
看代码演示:
class Animal{
constructor(name){
this.name = name
}
eat(){
console.log('我爱吃')
}
}
class Dog extends Animal{
constructor(name,age){
super(name)
this.age = age
}
say(){
console.log('我会汪汪叫')
}
}
let dog = new Dog('vip dog', 3)
</script>
左图说明instanceof问题
左图说明constructor问题
四、new运算符
new构造函数的原理:
- 生成一个空对象
- 将空对象的_proto_指向构造函数的prototype
- 执行构造函数,this上下文指向空对象
- 构造函数如果return了对象,放弃掉空对象;反之,返回前面的那个空对象