原型對(duì)象繼承
- ==原理:原型對(duì)象的屬性可以經(jīng)由對(duì)象實(shí)例訪問(wèn)==
- 下面的例子,所含【對(duì)象繼承】和【構(gòu)造函數(shù)繼承】,用于理解【原型屬性經(jīng)由對(duì)象實(shí)例訪問(wèn)】
//對(duì)象繼承
var person = {
name:"gs",
age:19
}
console.log(person.prototype === undefined );
function Student(){}
Student.prototype = person;//原型屬性經(jīng)由對(duì)象實(shí)例訪問(wèn)
console.log(new Student());
//構(gòu)造函數(shù)繼承
function Person(){
this.name = "gs";
this.age = 19;
}
function Student(){
this.name = "zk"
}
Student.prototype = new Person();//原型屬性經(jīng)由對(duì)象實(shí)例訪問(wèn)
var zk = new Student();
console.log(zk);
Object是頂層對(duì)象
- 所有對(duì)象都繼承自 Object.prototype,除非顯示指定
- 以對(duì)象字面量定義的對(duì)象,其 prototype 的值都被設(shè)為 Object.prototype
定義在 Object.prototype 上的方法
- hasOwnProperty
- propertyIsEnumerable
- isPrototypeOf
- valueOf | 返回對(duì)象的值表達(dá)
- toString | 返回對(duì)象的字符串表達(dá)
valueOf
- 每當(dāng)一個(gè)操作符被用于一個(gè)對(duì)象時(shí)(自動(dòng))調(diào)用
toString
- 在進(jìn)行運(yùn)算時(shí),有可能發(fā)生類型轉(zhuǎn)換
let obj = { name:"gs" };
console.log(obj+111)//;[object Object]111
console.log(obj.toString());//[object Object]
console.log(obj.valueOf());//{ "name": "gs" }
最好不要去修改 Object.prototype
最簡(jiǎn)單的一個(gè)對(duì)象繼承
- 聲明一個(gè)字面量對(duì)象,相當(dāng)于自動(dòng)繼承自 Object
- 聲明字面量對(duì)象,可以用 Object.create 方法替代,它的繼承作用更加明顯
- ==注意:Object.prototype 實(shí)際上值是 null==
var student1 = {
name:"gs"
}
var student2 = Object.create(Object.prototype,{
name:{
configurable:true,
enumerable:true,
value:"gs",
writable:true,
}
})
實(shí)現(xiàn)一個(gè)基本的對(duì)象繼承
//對(duì)象繼承
var person = {
name:"gs",
age:19
}
console.log(person.prototype === undefined );
function Student(){}
Student.prototype = person;//原型屬性經(jīng)由對(duì)象實(shí)例訪問(wèn)
console.log(new Student());
實(shí)現(xiàn)一個(gè)稍復(fù)雜的構(gòu)造函數(shù)繼承
- 因?yàn)閖s中的繼承是通過(guò)原型對(duì)象鏈來(lái)實(shí)現(xiàn)的,因此沒(méi)有調(diào)用對(duì)象父類的構(gòu)造函數(shù)
- 所以,要注意!最好重寫(xiě)構(gòu)造器屬性,否則將被設(shè)為父類的值
function Person(school,name,age){
this.school = "beijing univercity";
this.name = name;
this.age = age;
}
Person.prototype.sayName = function(){
console.log(this.name);
}
Person.prototype.sayAge = function(){
console.log(this.age);
}
function Student(name,age){
this.name = name;
this.age = age;
}
Student.prototype = new Person();
var gs = new Student("gs",19);
console.log(gs.constructor);//Person
Student.prototype.constructor = Student;//注意!要重寫(xiě)構(gòu)造器屬性,否則將被設(shè)為父類的值
console.log(gs.constructor);//Student
Student.prototype.sayName = function(){
console.log("student is "+this.name);
}
console.log(gs.sayName());
console.log(gs.sayAge());
實(shí)現(xiàn)一個(gè)偽類繼承(構(gòu)造函數(shù)竊?。?/h4>
- 實(shí)際上就是使用 call 的方式,將父類的屬性“拷貝”到子類中,同時(shí)還包括了constructor屬性
- 仍然需要用prototype方式繼承方法,同時(shí)還要設(shè)置constructor
function Person(school,name,age){
this.school = "beijing univercity";
this.name = name;
this.age = age;
}
Person.prototype.sayName = function(){
console.log(this.name);
}
Person.prototype.sayAge = function(){
console.log(this.age);
}
function Teacher(school){
Person.call(this,...arguments);//因?yàn)閠his指向Teacher,所以constructor屬性仍將是Teacher
this.school = school;//注意,新的屬性,應(yīng)置于繼承發(fā)生之后,以做覆蓋
}
var zk = new Teacher("haver","zk",23);
console.log(zk.constructor);//constructor屬性正確,為T(mén)eacher
console.log(zk.sayName === undefined);//true,但是,沒(méi)有繼承原型方法和屬性
Teacher.prototype = new Person();
var zk_2 = new Teacher("haver","zk_2",23);//沒(méi)有繼承原型方法
console.log(zk_2.sayName());//拿到方法了
console.log(zk_2.constructor);//Person。不是吧,constructor屬性又不對(duì)了
Teacher.prototype.constructor = Teacher;
console.log(zk_2.constructor);//Teacher。使用call方式繼承屬性,仍然需要用prototype方式繼承方法,同時(shí)還要設(shè)置constructor
父類方法被子類覆蓋,如何仍然可以調(diào)用?
function Person(name,age){
this.name = name;
this.age = age;
}
Person.prototype.sayName = function(){
console.log("father method " + this.name);
}
Person.prototype.sayAge = function(){
console.log(this.age);
}
function Student(){
Person.call(this,...arguments);
}
Student.prototype = Object.create(Person.prototype,{
constructor:{
configurable:true,
enumerable:true,
value:Student,
writable:true,
}
})
Student.prototype.sayName = function(){
console.log("child method");
}
Student.prototype.sayName_1 = function(){
Person.prototype.sayName.call(this);//這是唯一的訪問(wèn)父類的方法
}
var gs = new Student("gs",20);
console.log(gs);
console.log(gs.sayName_1());
創(chuàng)建一個(gè)沒(méi)有原型對(duì)象的對(duì)象
- 它不會(huì)發(fā)生和繼承來(lái)的屬性名相沖突的問(wèn)題,所以它是一個(gè)完美的【哈希容器】
- 哈希容器也可以理解為是一種映射容器,采用哈希算法(映射算法,散列算法),將不定長(zhǎng)的數(shù)據(jù)壓縮成定長(zhǎng)的數(shù)據(jù),這串定長(zhǎng)值我們稱為 哈希值
var obj = Object.create(null);
console.log(obj.prototype === undefined);
console.log( valueOf in obj);
console.log( toString in obj);
function Person(school,name,age){
this.school = "beijing univercity";
this.name = name;
this.age = age;
}
Person.prototype.sayName = function(){
console.log(this.name);
}
Person.prototype.sayAge = function(){
console.log(this.age);
}
function Teacher(school){
Person.call(this,...arguments);//因?yàn)閠his指向Teacher,所以constructor屬性仍將是Teacher
this.school = school;//注意,新的屬性,應(yīng)置于繼承發(fā)生之后,以做覆蓋
}
var zk = new Teacher("haver","zk",23);
console.log(zk.constructor);//constructor屬性正確,為T(mén)eacher
console.log(zk.sayName === undefined);//true,但是,沒(méi)有繼承原型方法和屬性
Teacher.prototype = new Person();
var zk_2 = new Teacher("haver","zk_2",23);//沒(méi)有繼承原型方法
console.log(zk_2.sayName());//拿到方法了
console.log(zk_2.constructor);//Person。不是吧,constructor屬性又不對(duì)了
Teacher.prototype.constructor = Teacher;
console.log(zk_2.constructor);//Teacher。使用call方式繼承屬性,仍然需要用prototype方式繼承方法,同時(shí)還要設(shè)置constructor
function Person(name,age){
this.name = name;
this.age = age;
}
Person.prototype.sayName = function(){
console.log("father method " + this.name);
}
Person.prototype.sayAge = function(){
console.log(this.age);
}
function Student(){
Person.call(this,...arguments);
}
Student.prototype = Object.create(Person.prototype,{
constructor:{
configurable:true,
enumerable:true,
value:Student,
writable:true,
}
})
Student.prototype.sayName = function(){
console.log("child method");
}
Student.prototype.sayName_1 = function(){
Person.prototype.sayName.call(this);//這是唯一的訪問(wèn)父類的方法
}
var gs = new Student("gs",20);
console.log(gs);
console.log(gs.sayName_1());
var obj = Object.create(null);
console.log(obj.prototype === undefined);
console.log( valueOf in obj);
console.log( toString in obj);