原型和继承
前端小白学习笔记,如果有什么错误,感谢各位大神的批评指正。。感谢,感谢!!
原型
__proto__和prototype的区别
每个函数function都有一个prototype,即显式原型(属性)
每个实例对象都有一个__proto__,即隐式原型(属性)
- __proto__是对象的隐式属性,prototype是对象的显式属性。
- 对象的隐式原型的值为其对应构造函数的显示原型的值。
本质上 原型是一个对象。
对象有原型
一般情况下,我们可以认为一个对象的原型就是它的父亲。
当我们创建一个对象时,默认有父亲。
例如 let app = {} app是有原型的,app.__proto__ == Object.prototype 就是他的原型,由于Object.prototype包含了一些方法,例如hasOwnProperty,因此app可以通过app.hasOwnProperty()调用。
就是说 儿子可以使用父亲的钱。
优先调用自身方法
如果自身没有对应方法,原型有,则会调用原型中的方法。
let son = {}
son.__proto__.show = function(){
console.log('我是父亲中的show')
}
son.show() //我是父亲中的show
//son没有show方法,但是父亲有,因此可以调用父亲中的show方法,
//即:儿子没有车,但是可以开父亲的车出去浪
//如果儿子也定义了同样的方法
let son = {show:function(){console.log('我是儿子中的show')}}
son.__proto__.show = function(){
console.log('我是父亲中的show')
}
son.show() //我是儿子中的show
//即:儿子有车,就开自己的车出去浪
创建一个无原型的对象
如何创造一个没有原型的对象(没有父亲的儿子?)
create作用是创建一个对象,第一参数是所创建对象的原型,第二参数是先创建对象的配置。
//完全数据字典对象 没有原型的对象
let hd = Object.create(null,{
name: {
value: '后人'
}
});
以上是普通对象的原型,接下来看看函数对象的原型。
函数的原型
默认情况下,一个普通对象只有一个原型,__proto__
但是一个函数对象默认有两个原型,__proto__和 prototype
- prototype中的方法是供给实例对象user使用的。即:User.prototype === user.__proto__
function User(){}
let user = new User()
User.prototype === user.proto //true
当在User的prototype定义一个show方法时,只能由user用,User不可以使用。
同理,在User的__proto__定义一个方法时,只有User用,user不可以用
User.prototype.show = function(){console.log('123')}
User.__proto__.show = function(){console.log('456')}
user.show(); //123
User.show(); //456
函数的原型和Object的关系
obj可以看做是由Object创建的实例对象,因此obj.__proto__ === Object.prototype
同理可得:
arr.__proto__ === Array.prototype
str.__proto__ === String.prototype
bool.__proto__ === Boolean.prototype
为什么原型的父亲是 Object 呢?
因为原型也是一个对象,对象的父亲不就是Object嘛?
原型的查看和修改
使用 Object.setPrototypeOf 和 Object.getPrototypeOf 修改和查看原型
Object.setPrototypeOf(hd,parent) //设置hd的原型为parent
Object.getPrototypeOf(hd) //查看hd的原型
constructor
prototype指向原型(父亲),constructor指向 指向原型的对象(儿子)
例如:
User.prototype.constructor == User
user.__proto__.constructor == User
如果我们想给原型添加方法
User.prototype.show = function(){}; //没有修改原型
User.prototype = { //这种方法修改了原型,
constructor:User //因此还需要配置默认的指针 constructor
show(){};
}
通过一个实例对象创建相同构造函数的其他实例。
即:通过儿子创建他的兄弟姐妹
//初始化构造函数
function User(name){
this.name = name
}
User.prototype.show = function(){
console.log(this.name)
}
let user = new User('xiaohan')
//通过user创建一个user2
//1.创建函数createByObject
function createByObject(obj, ...args){
//2.找到obj对应的构造函数User
let constructor = Object.getPrototypeOf(obj).constructor
//创建新实例对象
let obj2 = new constructor(...args)
return obj2
}
let user2 = createByObject(user,'haomi')
instanceof
检测 a 的原型链上有没有A的构造函数对应的prototype
a instanceOf A
代码演示:instanceof 用法
//先创建一个A的构造函数及实例化对象
function A(){}
let a = new A();
//在创建一个B 的构造函数及实例化对象
function B(){}
let b = new B();
//接下来,把b作为A的原型
A.prototype = b
console.log(a instanceof B) //false ?
console.log(a instanceof A) //false ???
console.log(a instanceof Object) //true 此时a的原型链上只有Object
console.dir(Object.get)
let aa = new A()
console.log(aa instanceof B) //ture
console.log(aa instanceof A) //true
为什么a对应的两个是false?
对比a 和 aa ,应该 先改变A.prototype,再创建实例对象
isPrototypeOf
判断a是否是b原型链上的一份子 a.isPrototypeOf(b)
区别:isPrototypeOf是直接判断两个对象的关系;
instanceof是判断一个对象和一个构造函数的原型的关系
let a = {}
let b = {}
//判断对象b是否是对象a的原型链上的一份子
console.log(b.isPrototypeOf(a)) //false
console.log(Object.isPrototypeOf(a)) //false
console.log(Object.prototype.isPrototypeOf(a)) //true
console.log(b.__proto__.isPrototypeOf(a)) //true
Object.setPrototypeOf(a,b)
console.log(b.isPrototypeOf(a)) //true
hasOwnProperty
检测属性是否存在
in 可以检测自身和原型链,但是hasOwnProperty只能检测自身属性
let a = {name : '123'};
let b = {url : '12321'};
Object.setPrototypeOf(a,b)
console.log('name' in a) //true
console.log('url' in a) //true
console.log(a.hasOwnProperty('name')) //true
console.log(a.hasOwnProperty('url')) //false
this
在原型中,this永远指向调用的对象。
继承
改变构造函数的继承 (错误)
function User(){}
User.prototype.show = function(){console.log('123')};
//接下来定义另一个实例对象,并让他继承User的方法
function Admin(){}
Admin.prototype.view= function(){console.log('456')};
Admin.prototype = User.prototype
let ad = new Admin;
ad.show()
ad.view() //Uncaught TypeError: ad.view is not a function
此时ad使用的是User的prototype,丢失了view方法。
改变构造函数的继承可以理解为:儿子为了继承父亲的遗产,把自己已有的钱全扔了。
原型的继承
不要让Admin直接继承,而是让它的原型去继承
Admin.prototype.\_\_proto\_\_ = User.prototype
此时Admin可以同时使用两种原型的方法。
第一种方法是Admin换了个爸爸,第二种方法是爸爸给Admin找了个爷爷。