一,对象的方法
1, setPrototypeOf 和 getPrototypeOf
//__proto__链
//在es6中可以在对象内直接操作__proto__
let obj1={name:'wdwd'};
let obj2 = {age :8};
// obj1.__proto__ = obj2;
Object.setPrototypeOf(obj1,obj2);
console.log(Object.getPrototypeOf(obj1));//{ age: 8 }
2, super
let obj2 = {
age:10,
name:'erer'
};
let obj = {
name:'adawd',
getPName(){//可以通过super关键字获取到父类的属性
return super.name
},
__proto__:obj2
}
console.log(obj.getPName());//erer
二,继承
在es5中没有类的概念, 只有构造函数
在es6中 有class关键字
类的属性 三种属性:公有属性(__proto__),私有属性,静态方法(静态属性)
function Parent(){
// 构造函数中的this,通过new调用的那么this指代的是实例
this.name = 'parent';
}
Parent.prototype.eat=function () {
console.log('eat');
}
let parent = new Parent();
parent.__proto__.eat();//会先找私有属性,找不到再去找公有属性
console.log(Parent.prototype.constructor === Parent);//true
1. 继承私有属性:
只有call方法改变this指向才可以
function Parent(){
this.name = 'parent';
this.eat = function(){
console.log("eat");
}
}
function Child(){
this.name = 'child';
Parent.call(this);
}
let child = new Child();
console.log(child.eat());
2. 继承公有属性:
-
Child.prototype=Parent.prototype
这种方法会使他们变成兄弟关系,而不是继承关系。(大多数人使用这种方法其实是错误的,虽然它还是能拿到Parent原型上的属性,但是它破坏了这种继承关系) -
第一种方式:
Child.prototype.__proto__= Parent.prototype
等价于Object.setPrototypeOf(Child.prototype,Parent.prototype)
Parent.prototype.say= "saying";
function Parent(){
}
function Child(){
}
Object.setPrototypeOf(Child.prototype,Parent.prototype);//==Child.prototype.__proto__= Parent.prototype
let child = new Child();
console.log(child.say);//saying
- 第二种方式:
Child.prototype = Object.create(Parent.prototype)
. ,只继承公有属性
Parent.prototype.say= "saying";
function Parent(){
}
function Child(){
}
Child.prototype = Object.create(Parent.prototype);
let child = new Child();
console.log(child.say);//saying
console.log(child.constructor)//[Function: Parent]有一个小毛病,就是,它找到的构造出它的函数是Parent而不是Child
为什么会出现这种毛病,来分析一下Object.create(Parent.prototype)
的原理
//圣杯模式
function create(parentPrototype){
function Fn(){};
Fn.prototype = parentPrototype;
return new Fn();
}
Child.prototype = create(Parent.prototype);
let child = new Child();
//就是下图中的紫色线条的路线,那么child找constructor,实例上没有constructor,
//去原型上找constructor属性,原型就是实例fn,一个实例它也没有constructor属性,只能再去它的原型parentPrototype上找,
//parentPrototype原型上的constructor当然指向Parent,所以导致一个错误就是child找constructor居然是Parent。
第一种处理构造函数指向错误的方法:
Parent.prototype.say= "saying";
function Parent(){
}
function Child(){
}
Child.prototype = Object.create(Parent.prototype,{constructor:{value:Child}});
let child = new Child();
console.log(child.constructor)//[Function: Child]
第二种处理构造函数指向错误的方法:
Parent.prototype.say= "saying";
function Parent(){
}
function Child(){
}
function create(parentPrototype,props){
function Fn(){};
Fn.prototype = parentPrototype;
let fn = new Fn();
for(let key in props){
Object.defineProperty(fn, key, {
...props[key],
enumerable:true
});
}
return fn;
}
Child.prototype = create(Parent.prototype,{constructor:{value:Child}});
let child = new Child();
console.log(child.say);//saying
console.log(child.constructor);//[Function: Child]
-----------------------------------------------------------------------------------
//以下例子解释一下 Object.defineProperty()方法的用法
let a = {}
// a.name =1;
// ES5的一个方法来添加属性:
Object.defineProperty(a,'name',{
//前三个属性是可选的
enumerable:true,//表示这个属性是否可以被枚举出来
configurable:true,//表示这个属性是否可以被删除
writable:true,//表示这个属性是否可以被写入(更改)
value : 1
});
console.log(a.name);//1
------------
let b = {};
Object.defineProperty(b,'name',{
//前三个属性是可选的
enumerable:true,//表示这个属性是否可以被枚举出来
configurable:true,//表示这个属性是否可以被删除
// writable:true,//表示这个属性是否可以被写入(更改)
//当有set和get的时候,writable属性就不能写。
get(){
console.log('get');
return 1;
},
set(val){
console.log('设置值')
}
});
b.name = 'asd';//当给该对象设置属性的值时候,会自动调用set,打印“设置值”
console.log(b.name);//当取出属性值得时候,会自动调用get,打印“get”,还有返回值