原型
JavaScript中的原型
prototype是一个给对象提供共享属性的对象,也就是prototype也是一个对象,保存一些共享属性
怎么让一个对象为另一个对象提供属性的访问
原型为构造函数的实例化对象提供了一个公共的空间,来存放一些共享属性,怎么让实例化对象,来访问这些公共属性
通过隐式原型的引用,每一个对象都有一个隐式原型
在我们创建对象的时候,对象被挂载了另外一个 _ _ proto _ _ 这个属性,值是一个对象,隐式就是并不是开发者自己创建的属性
怎么访问
- Object.getPrototypeOf(obj)方法,访问一个对象的原型
- Object.setPrototypeOf(obj, anotherObj )方法,设置一个对象的隐式原型指向另一个对象prototype
- 通过实例化对象上的_ _ proto _ _进行访问
试着将一个对象的原型设置为另一个对象
let abj1 = {
a: 1
}, obj2 = {
b: 2
}
// 也就是任意能提供公共属性给其他对象访问,就是prototype,现在的obj2就是obj1的原型
Object.setPrototypeOf(obj1, obj2)
实例对象创建时,要将实例对象的隐式原型指向构造函数prototype
原型链
prototype是一个提供共享属性的对象,作为对象,就有隐式原型,指向创建它的构造函数的显示原型,直到隐式原型为null
函数
一个普通的函数在创建时,自带了一个prototype属性,这个属性的隐式原型指向Object.prototype
创建一个对象
let obj = {a: 1, b: 2} 经历了什么
- 创建一个空对象
- 指定空对象的prototype
- 给这个空对象(已指定prototype)初始化属性
// 假设并没有隐式指定prototype,就是一个什么都没有的空对象,每个对象
// 默认身上都有一个隐式原型,但假设此时没有指定它的prototype,通过new操作符
// 或者字面量方式创建,会一步完成上面这三步,完成的事情
let obj = {};
//这一步就是将obj.__proto__ = Object.prototype,所以__proto__看到的值就是Object.prototype的值了
Object.setPrototypeOf(obj, Object.prototype);
//初始化属性
obj.a = 1; obj.b = 2;
通过Object.create()
-
该方法有两个参数,arg1是要给新建的这个对象指定的prototype;arg2(可选参数)是一个非undefined的对象,指定创建对象的初始化自身的可枚举属性
let obj = Object.create(Object.prototype, { a: { value: 1, enumerable: true }, b: { value: 2, enumerable: true } })就完成了上面三步的操作,隐式的做完了这一切
通过构造函数的形式
内置的一些构造函数
Array Object Number String Boolean
通过new 调用构造函数的方式创建,同时也是完成了上面的那三步操作
就像new操作符做的事
- 创建一个空对象 (第一步,创建空对象)
- 指定这个空对象的_ _ proto _ _为构造函数的prototype【每个对象默认携带一个 _ _ proto _ _ 属性,每个函数默认携带一个prototype】 (第二步,指定原型)
- 调用构造函数,并指定构造函数的this,为当前的空对象,执行构造函数和的代码(第三步,初始化对象自身的可枚举属性)
- 判断构造函数的返回值是否为函数或者对象,如果是就返回构造函数的返回值,否就返回上面创建的那个对象
通过class形式
先看一下class定义构造函数的结构
class Person {
// constructor
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
// 【计算属性部分】
// getter
get personInfo() {
return this.firstName + ' ' + this.lastName
}
// setter
set personInfo(newValue) {
this.firstName = newValue.split(' ')[0];
this.lastName = newValue.split(' ')[1];
}
// 【实例化对象公共方法部分,也就是prototype】
// method
showMyself() {
console.log(`大家好,我的名字叫${this.personInfo}`)
}
// 【构造函数内部属性】
// static method
static toUpperCaseName(thisArg) {
return thisArg.personInfo.toUpperCase();
}
// static attr
static constructorName = 'Person';
// 【实例化对象内部属性】每个实例化对象都有
toLowerCaseName = function(thisArg) {
return thisArg.personInfo.toLowerCase();
}
constructorName1 = 'Person';
}
下面分析一下上面class语法糖的结构
constructor构造器部分:就相当于构造函数内部的代码部分,放实例化对象私有的属性,也就是每个实例化对象他们属性键值对,键相同,值不同
getter和setter计算属性部分:主要存放一些通过实例对象属性构成的一些表达式
method公共对象【prototype】部分:用在存放实例化对象的一些公共的方法
实例化对象内部属性:也就是实例化对象,都有的键值对相同的一些属性,但每个实例化对象关于这些属性键值对的存储地址不同
static构造函数内部属性:在构造函数这个对象身上存放一些属性值或方法
现在看一下实例化一个person对象
先查看一下Person构造函数
在看一下实例化对象person
class完成的步骤和构造函数相同,继承方法依托于prototype对象
class中的extends和super,完成两个构造函数之间的继承
class Person {
// constructor
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
// getter
get personInfo() {
return this.firstName + ' ' + this.lastName
}
// setter
set personInfo(newValue) {
this.firstName = newValue.split(' ')[0];
this.lastName = newValue.split(' ')[1];
}
// method
showMyself() {
console.log(`大家好,我的名字叫${this.personInfo}`)
}
// static method
static toUpperCaseName(thisArg) {
return thisArg.personInfo.toUpperCase();
}
// static attr
static constructorName = 'Person';
// 实例化对象都有的属性名和值
toLowerCaseName = function (thisArg) {
return thisArg.personInfo.toLowerCase();
}
constructorName1 = 'Person';
}
class Student extends Person {
constructor(firstName, lastName) {
super(firstName, lastName);
}
}
let person = new Person('zhang', 'san');
let student = new Student('wang', 'wu');
完成继承就是修改原型,Student.prototype.constructor = Person; Object.setPrototypeOf(Student.prototype, Person.prototype)完成原型链的继承,通过call方法执行Person构造函数实现对于属性的继承,在Student构造函数中执行了Person.call(this, firstName, lastName)
如上图所示,只要是实例对象上的静态属性、静态方法、动态属性都继承了,原型也实现了绑定
问题
什么是原型
原型就是一个存放公共属性的对象,在JavaScript中每一个对象都有一个隐式引用_ _ proto _ _ ,每一个对象都可以作为另一个对象的原型用来存放一些公共的属性
原型链是什么,有什么作用
原型是一个对象,每一个对象里面都有一个 _ _ proto _ _隐式引用,指向它构造函数的prototype或者null,这样就形成了原型链,用于保存一些公共属性
原型链的作用,在访问一个对象的属性的时候,会现在当前对象属性上查找,如果找不到会沿着原型链查找,直到null为止,找到了就返回值,找不到就返回undefined
怎么实现原型的继承
有两种方式实现原型链的继承,一种是Object.create(prototype)这种形式 , 另外一种是Object.setPrototypeOf(实例对象, 指向的原型对象)