原型与原型链
一.在了解原型之前需要提前了解的。
-
1.工厂模式:创建一个函数,用特定的接口创建对象的细节。
//现在要创建两个包含 “name”和“age”的对象, let tom ={name:"Tom",age:16} let lily = { name : "Lily",age:18} ……//所示数量足够具大 ,对象足够大 ,会花费大量的时间。下面的工厂模式能 很好的解决这一问题
//工厂的就是只流水线不是所有都是要人工,节约人力成本。 function person(name,age){ let obj = {}; //创建一个对象 ; obj.name = name ; //为对象添加细节 obj.age = age ; obg.sayHello= function (){ alert ("Hello"+this.name) }; return obj;} //返回这个对象 let tom = person("Tom",16); let lily = person("Lily",18)
- 工厂函数的优势:避免的大量的重复代码;
- 工厂函数的劣势:其创建的对象不能标志为一种特定的类型,没有解决对象识别的问题,不知道对象的类型。构造函数能很好的解决这个问题。
-
2.构造函数:自定义构造函数,可以自定义对象类型的属性和方法。
function Person(name,age){ this.name = name ; //为对象添加细节 this.age = age ; this.sayHello= function (){ alert ("Hello"+this.name) }; let tom = new Person("Tom",16); let lily =new Person("Lily",18)
- new的过程做了三件事
①
创建了一个对象;②
将this
指向这个对象;③
返回这个对象; - 两个实例对象都有一个属性
constructor
(构造函数),指向Person
;这就是可以通过constructor
判断对象类型的原理。 - 存在的问题:构造函数的每个方法都要在实例上重新创建一遍,虽然函数名是一样的,但是不相等的。
- new的过程做了三件事
二.原型模式
-
1.如下,与构造函数模式不同的是,原型模式的每个实例都是访问同一属性同一函数,,函数不用重新创建。
function Person () { this.x = 100; } Person.prototype.name = 'Tom'; Person.prototype.age = 18; Person.prototype.sayHello = function (){ alert(`Hello${this.name}`) } let Tom = new Person() Tom.sayHello()
-
2.原型对象
- ①每个函数数据类型(普通函数,类)上,都有一个属性,叫
prototype
,是一个对象,这个函数指向函数的原型对象; - ②
prototype
这个对象上,自带一个属性,constructor
指向当前这个类; -
③当为实例添加属性时,这个属性会屏蔽原型对象中保存的同名属性,但是事实阻止访问,并没有修改那个属性,若将同名的实例属性设置为
null
,同样会屏蔽,但是若用delete
,则可以删除实例属性,可以重新访问原型中的属性。alert(Tom.age); //18 let Tom.age = 20; alert(Tom.age); //20 delete Tom.age; alert(Tom.age); //18
- ④属性分为两种,来自实例(或者是构造函数)或是原型,原型上的属性和方法都是共有的,构造函数中的属性方法都是私有的,构造函数中的
this
都是实例。为什么私有属性(来自实例的属性)的查找等级要高呢?这就涉及到原型链。
- ①每个函数数据类型(普通函数,类)上,都有一个属性,叫
-
3.原型链:每个对象数据类型(普通对象,
prototype
,实例)都有一个属性,叫做__proto__
;- 比如我们
console.log(Tom.age)
的查找过程是怎样的呢?①首先在私有空间内查找age属性,私有空间的属性包括自身的属性和从类那里继承的属性, - ②找不到的话:通过
__proto__
去当前实例所属类的原型上进行查找,找到的话,说明是共有属性; - ③还找不到的话:继续通过
__proto__
去当前实例所属类的原型进行查找,找不到将继续通过__proto__
一直找到Object
。
- ④曲线
①
代表Person
的原型对象;曲线②
中,实例Tom
通过__proto__
指向Tom
所属类(Person
)的原型(Person Prototype
);曲线③中,Person的原型对象通过__proto__
找到Person
对象的所属类,也就是Object
(函数也是对象类,万物皆对象),指向它的原型(ObjectPrototype
) ;曲线5
中,指向Obeject
所属类的原型,它的类就是它自己,所以此时不在有__proto__
整个属性查找结束,这就是原型链的查找过程。
-
⑤通过
hasOwnProperty
来判断属性,这个方法就是通过④中的查找过程,在基类Object
中找到的。 判断属性是否在对象上“name” in Tom
,其中in
的查找过程也是通过上述的查找过程。function hasPrototypeProperty(object,attr){ return !object.hasOwnProperty(attr) && (attr in object);}
- 比如我们
-
4.关于原型需要注意的几点
-
①使用简单原型语法的时候,注意
constructor
的指向问题,Person.prototype={ //此时constructor指向Object构造函数 name : 'Tom', age:18 } Person.prototype={ //此时constructor指向Person constructor:Person, name : 'Tom', age:18 }
- ②添加和修改原型的属性和方法都能立即在所有对象实例中反应出来(即使先创建实例后修改原型);但是如果重写整个原型对象,创建在前的实例并不能获得重写后的属性或方法。这是因为重写原型之后是新生成原型对象,和声明在前的任何已经存在的实例都没有关系。
-
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。