__proto__严格意义上并不是一个属性
__proto__严格意义上并不是一个属性,而是getter和setter进行是否为对象来判断是否取或者设置值的
如果设置对象
let obj = {}
obj.__proto__ = {
name: 'han'
}
console.log(obj.__proto__);//han
此时有继承对象里面有个属性name为han
如果设置基本数据类型
let obj = {}
obj.__proto__ = "嘻嘻"
console.log(obj.__proto__);
此时原型并没有 "嘻嘻"这个属性
我们再认真看下proto
此时我们可以确定proto利用了getter和setter来判断是否为对象来设置的
继承的方法
1.用Object.setPrototypeOf
let obj = {
name: 'han'
}
let tem2 = {
name: '韩',
show: function() {
console.log(this.name);
}
}
Object.setPrototypeOf(obj,tem2)
console.log(obj.__proto__ === tem2);//true
2. 用es6语法糖class
class A{}
class B extends A{}
console.log(B.__proto__.__proto__ === A.__proto__);//true
console.log(B.__proto__ === A);//true
3.直接.__proto__
function A(){}
function B(){}
A.__proto__ = B;
4.利用Object.create
let obj = {}
let hj = {
show: function(){
console.log('你被继承啦~');
}
}
obj = Object.create(hj)
console.log(obj.__proto__ === hj);//true
此方法只能定义原型,不能获取后面追加的属性。例如:、
let obj = {}
let hj = {
show: function(){
console.log('你被继承啦~');
}
}
obj = Object.create(hj,{
home:{
wen: 'home'
}
})
console.log(Object.getPrototypeOf(obj));//只能获取到show方法而无法拿到home属性
_proto_是服务于函数对象的,prototype是服务于构造函数的实例化对象的
js的函数会有一个默认的prototype对象,这个prototype对象用来指定函数的继承关系,prototype对象默认有两个属性,一个是constructor,另一个就是proto属性,默认的prototype对象在被改变之前就像是这个函数用来表示自己的一个对象,其中proto属性和普通对象的proto属性一样用来对应继承关系
console.log(User.__proto__ === Object);//false
console.log(User.__proto__ === Object.__proto__);//true
console.log(User.prototype.__proto__ === User.__proto__.__proto__);//true
console.log(User.prototype.__proto__ === Object.prototype);//true
当我们只设置_proto_时
function User(){};
User.__proto__.view = function(){
console.log("User View method");
};
/*
User本身能够像对象一样调用原型的属性,说明_proto_是服务于函数对象的
hd是User的实例化对象,但是此时报错未定义。
说明只有User的prototype设置的属性才可以使用
说明prototype是服务于构造函数的实例化对象的
*/
User.view();//User View method
let hd = new User();
hd.view();//Uncaught TypeError: hd.view is not a function
当我们设置prototype:
function User(){};
User.prototype.name = "houdunren"
let hd = new User();
/*
说明只有User的prototype设置的属性才可以使用
说明prototype是服务于构造函数的实例化对象的
*/
console.log(hd.name);//houdunren
此时的的指向图为:
(插一下小知识点:但我们设置了
User.__proto__.view = function(){
console.log("User View method");
};
之后,Object的原型也会有这个view函数 此时打印一下Object:
console.dir(Object);
结果:Object的原型也会有这个view函数
但是同样设置prototype.name的prototype不会有这个实例,这也再次说明了prototype是为创建的对象实例服务的:
此时我们输入:
console.log(User.prototype.__proto__ === Object.prototype);//true
console.log(User.__proto__ === Object.__proto__);//true
此时的图说明
)
原博客:www.cnblogs.com/onepixel/p/…
这篇博客讲的也很好!!:blog.csdn.net/u013448536/…
在Javascript中,万物皆对象,但对象也有区别,大致可以分为两类,即:普通对象 Object 和 函数对象 Function。
function f1() {
// todo
}
varf2 = function () {
// todo
};
varf3 = newFunction('x', 'console.log(x)');
varo1 = {};
varo2 = newObject();
varo3 = newf1();
console.log(
typeoff1,
typeoff2,
typeoff3,
typeofo1,
typeofo2,
typeofo3
);
在 JS 中,每当创建一个函数对象 f1 时,该对象中都会内置一些属性,其中包括 prototype 和 proto, prototype 即原型对象,它记录着f1的一些属性和方法。
需要注意的是,prototype 对 f1 是不可见的,也就是说,f1 不会查找 prototype 中的属性和方法。
function f(){}
f.prototype.foo = "abc";
console.log(f.foo); // undefined
那么,prototype 有什么用呢? 其实 prototype 的主要作用就是继承。 通俗一点讲,prototype 中定义的属性和方法都是留给自己的 “后代” 用的,因此,子类完全可以访问prototype中的属性和方法。
想要知道 f1 是如何把 prototype 留给“后代”,我们需要了解一下 JS 中的原型链。此时,JS中的 proto 入场了,它存在于普通对象和函数对象中,它的作用就是引用父类的 prototype 对象,JS在通过 new 操作符创建一个对象的时候,通常会把父类的 prototype 赋值给新对象的 __proto__属性,这样就形成了一代代传承...
function f() {}
f.prototype.foo = "abc";
varobj = newf();
console.log(obj.foo); // abc
如图所示,f.prototype 的 proto 中保存的是 Object.prototype,Object.prototype 对象中也有 proto,而从输出结果看,Object.prototype.proto 是 null,表示 obj 对象原型链的终结。如下图所示:
总结
-
原型链的形成真正是靠__proto__ 而非prototype,当JS引擎执行对象的方法时,先查找对象本身是否存在该方法,如果不存在,会在原型链上查找,但不会查找自身的prototype。
-
一个对象的 proto 记录着自己的原型链,决定了自身的数据类型,改变 proto 就等于改变对象的数据类型。
-
函数的 prototype 不属于自身的原型链,它是创建子类的核心,决定了子类的数据类型,是连接子类原型链的桥梁。 在原型对象上定义方法和属性,是为了被子类继承和使用。
-
改变原型跟this指向没有关系,例如:
let obj = {
name: 'han'
}
let tem2 = {
name: '韩',
show: function() {
console.log(this.name);
}
}
Object.setPrototypeOf(obj,tem2)
console.log(obj.show());//输出han,此时虽然obj原型是tem2并且调用的是来自于tem2的show方法,但此时this还是指向调用者obj