[JavaScript]原型链是什么
原型链
函数上属性 prototype【原型】指向一个对象【原型对象】–> 对象上存在一个 [[prototype]] 属性指向这个对象的构造函数的prototype指向的原型对象, 这样就不断构成了一个链条,就是原型链
js
function Parent() {
this.name = 'wang da'
this.age = 12
}
Parent.prototype.getName = function () {
return this.name
}
console.log(Parent.prototype)
console.log(Object.getPrototypeOf(Parent.prototype) === Object.prototype)
从第一个打印中可以看到函数Parent的原型对象上有一个默认的constructor属性指向自身,这个原型对象上有一个[[prototye]] 属性指向Object.prototype
从第二个打印中可以看到 原型对象上的[[prototype]]属性指向了Object.prototype, 验证了图中所述的原型链的关系
可以看到链条中关键的连接是[[prototype]] 对应对象上的属性; prototype 对象函数上的属性,理解这两点就可以理解原型链
[[prototype]] 每一个对象上都会有这样一个属性(除非使用 Object.create(null)创建对象),它指向创建这个对象的构造函数上的prototype所对应的原型对象
prototype: 函数上的prototype属性,指向一个对象,该对象中默认有一个contructor属性指向函数本身
实现继承的方式
- 原型继承
优点:原型继承可以方便的继承到父类原型上的方法与属性
缺点:引用类型的数据共享一份内存,容易导致多个实例对象操作同一份数据,导致对象数据紊乱
js
function Parent() {
this.name = 'wang da'
this.age = 30
this.subjects = ['math', 'english']
}
Parent.prototype.getName = function () {
return this.name
}
function Child() {
this.name = 'wang er'
this.age = 6
}
// 将父类的原型对象赋值给子类的原型
Child.prototype = new Parent() // -- 创建一个对象,对象 __proto__ 指向父类的原型对象
// 修正子类原型对象的构造函数指向
Child.prototype.constructor = Child
const child_1 = new Child()
const child_2 = new Child()
// chid_1 与 child_2 引用的都是原型对象上的 subjects 会导致引用类型时多个实例操作同一份数据
child_1.subjects.push("child_1")
console.log(child_1.subjects) // ['math', 'english', 'child_1']
console.log(child_2.subjects) // ['math', 'english', 'child_1']
// 从打印可以看出,child_2实例上的subjects属性同样被child_1中修改了
- 构造函数继承
在子构造函数内部调用父构造函数,并绑定为子类的this, 从而实现继承父构造函数的属性与方法,但是继承不到父构造函数prototype上的属性与方法
js
fuction Child() {
Parent.call(this)
this.lastName = 'child'
}
- 组合继承
结合原型链继承与contructor继承
js
// 结合构造函数继承与原型继承两种方式
function Child() {
Parent.call(this)
}
Child.prototype = new Parent()
Child.prototype.constructor = Child
- Object.create()
可以用于创建一个对象,第一个参数为对象或null, 第二个参数是新对象数据描述符【可选】
js
// 用于创建绑定原型,避免多一次创建new
Child.prototype = Object.create(Parent.prototype)
// 第二个参数属性描述符
const obj = Object.create({}, {
name: {
value: 'wang',
writable: false,
enumerable: false,
}
})
- class 继承
js
class Person {
firstName = 'wang'
age = 30
subjects = ['math', 'english']
constructor(name) {
this.father_fullName = this.firstName + '_' + name
}
}
class Child extends Person {
constructor(fatherName, childName) {
super(fatherName) // 调用父类构造函数
this.child_fullName = this.firstName + '_' + childName
}
}
const child_1 = new Child('ddasd', 'dasdas')
补充 new 创建对象的过程
- 创建this对象
- 给创建的this对象绑定构造函数的prototype原型属性作为 new 对象的原型对象
- 执行构造函数方法, 将this绑定到新对象上
- 默认return this, 除非显式返回一个object
根据以上过程可以,可以自定义一个new的函数
js
function myNew(constructor) {
// 创建对象
const obj = {}
// 绑定 __proto__
Object.setPrototypeOf(obj, constructor.prototype)
// 执行构造函数,给构造函数中的this绑定为创建的对象
const res = constructor.apply(obj, Array.prototype.slice.call(arguments, 1))
// 如果构造函数显式返回的是对象就返回这个对象,否则就是返回创建的对象
return res instanceof Object ? res : obj
}
const obj = myNew(Parent, 'dadadasd')
发表评论