一.原型
(1).原型知识拓展
![](https://img-blog.csdnimg.cn/20201130100850137.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1llc3RlcmRheV9Ub21vcnJvdw==,size_16,color_FFFFFF,t_70)
(1).__proto__ 和constructor属性是对象所独有的;
(2).prototype属性是函数所独有的;因为函数也是一种对象,所以也拥有__proto__和constructor属性
2.__proto__属性的作用就是当访问一个对象的属性时,如果该对象内部不存在这个属性,,那么就会去它的__proto__属性所指向的那个对象(父对象)里找,直到找到__proto__属性的终点null,再往上找就相当于在null上取值,会报错。通过__proto__属性将对象连接起来的这条链路即我们所谓的原型链
3.prototype属性的作用就是让该函数所实例化的对象们都可以找到公有的属性和方法,即f1.__proto__ === Foo.prototype
4.constructor属性的含义就是指向该对象的构造函数,所有函数最终的构造函数都指向Function
(2).原型改变
.__protorype__这种方式非常影响性能,建议采用下方get set
常规做法
var person = new Person();
person.__proto__ = {}
//语义化不好,且是内部属性
//访问效率慢
//所有继承子该原型的对象都会影响到
新做法
Object.setPrototypeOf(person,{});
(3).Object.setPrototypeOf/Object.getPrototypeOf
let proto = {
y: 20,
z: 40
}
let obj = {x: 10};
let obj1 = Object.setPrototypeOf(obj,proto);
log(obj1 === obj) // true;所以直接调用就可以了
log(obj)
//{x:10
__proto__:
y:20
z:40
}
(4).第一个参数为值类型
会自动转换第一个参数为对象,但是要根据情况判断能否把第二个参数放在第一个的原型上
let obj = Object.setPrototypeOf(1,{});
log(obj); //1
let obj = Object.setPrototypeOf(1,{a:1,b:2});
log(obj);//Number{0,...一系列方法}
原因是第一次传的是空对象没有生效,第二个生效了,但是是通过包装类包装后,默认值则为0,
证明这样的方式是无效的
log(Object.getPrototypeOf(1) === Number.prototype)//true
所以系统无法将第二个参数放到指定原型,直接通过包装类指定了,所以第二个参数指定失败了
所以如果第一个参数不是对象,那么就代表者指定不会有任何效果,原型会是原本的构造函数的原型
第一个值为字符串类型boolean类型都与上方结果一致,不做演示
二.四种遍历方式
(1).keys/values
const foo = {
a: 1,
b: 2,
c: 3
}
Object.defineProperties(foo,{
d:{
value: 4,
enumerable: true
},
f:{
value: 5,
enumerable: false
}
})
log(Object.keys(foo));
//['a','b','c','d']
不可枚举的无法获取,继承属性无法获取valus 同理,获取的为值
(3).entries
log(Object.entries(foo));
["a",1]["b",2]["c",3]["d",4]
(4).字符串
let obj = '123'
log(Object.keys(obj));
//[0,1,2]
//1和true 都是[]
//un和null会报错
三.super
let proto = {
y: 20,
z: 40
}
let obj = {
x : 10,
foo: super.y // 报错
foo:()=>{
log(super.y) // 报错
}
}
Object.setPrototypeOf(obj,proto);
obj.foo();
let proto = {
y: 20,
z: 40,
bar(){
this.y
}
}
let obj = {
x: 10,
foo(){
log(super.y);
},
doo(){
super.bar();
}
}
Object.setPrototypeOf(obj,proto);
obj.foo();//20
原型的方法也能访问
obJ.doo();//20
四.symbol
(1).原始值类型
String Number Boolean null un symbol
(2).各类特征
let s1 = Symbol();
let s2 = Symbol();
log(s1 === s2);//false
let s1 = Symbol();
let s2 = Symbol();
log(typeof s1);//symbol
let sq = Symbol();
sq.a = 1;//挂不上属性
log(sq.a)//输出Un
let s1 = Symbol('foo')
var obj = {a: 1};
let s1 = Symbol(obj);
log(s1); //Symbol([object Object])
let s1 = Symbol(null);
log(Object.getPrototypeOf(s1));
let s1 = Symbol(null);
log(s1.toString());//symbol(null)
let s1 = Symbol(null);
log(s1+'');//报错
log(!s1);//false
log(s1+1)报错
let name = Symbol();
let person = {};
person[name] = 'zhangsan';
log(person);//{Symbol():"zhangsan"}
通过symbol来声明 .name就是字符串访问了所以不行
let name = Symbol();
let person = {
[name]: 'zhangsan'
};
log(person);//{Symbol():"zhangsan"}
defineProperty
Object.defineProperty(person, name, {
value: 'zhangsan'
})
log(person);//{Symbol():"zhangsan"}
log(person.name);//un
正确使用方式
let name = Symbol();
let eat = Symbol();
let person = {
[name]: 'zhangsan',
[eat](){
log(this[name])
}
}
person[name]();
(2).Symbol.for()/Symbol.keyFor()
let s1 = Symbol('foo');
let s2 = Symbol('foo');
log(s1 === s2);//就算标识符一致也打印false
let s1 = Symbol.for('foo');
let s2 = Symbol.for('foo');
log(s1 === s2);//true
let s1 = Symbol('foo');
let s2 = Symbol.for('foo');
log(s1 === s2);//false
let s1 = Symbol('foo');
let s2 = Symbol.for('foo');
log(Symbol.keyFor(s1));//un
log(Symbol.keyFor(s2));//foo
(3).遍历
const obj = {}
let a = Symbol('a');
let b = Symbol('b');
obj[a] = 'hello';
obj[b] = 'world';
obj.c = 'hh'
log(obj)
for(let i in obj){
log(i)
}//{c:haha}
var obj1 = {}
Object.assign(obj1 ,obj);
log(obj1 );
{
c:'hh'
Symbol(a): 'hello'
Symbol(b): 'word'
}
我虽然能显示,但是我怎么才能调用呢?
如下
const objectSymbols = Object.getOwnPropertySymbols(obj);
log(objectSymbols);
//[
0:Symbol(a)
1:Symbol(b)
]
const obj = {c:1, d:2};
let a = Symbol('a');
let b = Symbol('b');
let _a = Symbol('_a');
let _b = Symbol('_b');
obj[a] = 'hello';
obj[b] = 'world';
Object.defineProperties(obj,{
e:{
value: 5,
enumerable: true
},
f:{
value: 6,
enumerable: false
},
[_a]:{
value: -1,
enumerable: true
},
[_b]:{
value: -2,
enumerable: false
},
})
let h = Symbol('h');
let i = Symbol('i');
let j = Symbol('j');
const obj1 = {
g: 7,
[h]: 8
}
Object.defineProperties(obj1,{
[i]:{
value: 9,
enumerable: true
},
[j]:{
value: 10
},
k:{
value: 11
}
})
Object.setPrototypeOf(obj, obj1)
console.log(obj)
{
c: 1
d: 2
e: 5
f: 6
Symbol(a): "hello"
Symbol(b): "world"
Symbol(_a): -1
Symbol(_b): -2//灰色
__proto__:
g: 7
k: 11 //灰色
Symbol(h): 8
Symbol(i): 9
Symbol(j): 10//灰色
__proto__: Object
}
可枚举不可枚举 原型上的 是symbol的
for(let i in obj){
console.log(i)
}
c d e g
可枚举的 不是Symbol的 原型上的也出来
console.log(Object.keys(obj))
[
0: "c"
1: "d"
2: "e"
]
可枚举的 不是symbol的 不是原型的
console.log(Object.getOwnPropertySymbols(obj))
[
0: Symbol(a)
1: Symbol(b)
2: Symbol(_a)
3: Symbol(_b)
length: 4
]
不是原型的 不管你枚举不枚举
var obj3 = {}
Object.assign(obj3,obj);
console.log(obj3)
{
c: 1
d: 2
e: 5
Symbol(a): "hello"
Symbol(b): "world"
Symbol(_a): -1
}
自身的,可枚举的 包含Symbol
Json.stringify()//遍历自身可枚举的