一些原型的理解(1)
1.初识原型
每个函数都有一个 prototype 属性,通过new构造函数,每一个js对象(null除外)在创建的时候就会关联另一个对象(就是我们所说的原型),每一个对象都会从原型"继承"属性(因为每个对象至少会有一个原型object)。
每一个js对象(除了 null )都具有的一个属性,叫__proto__,这个属性会指向该对象的原型。
每个原型都有一个 constructor 属性指向关联的构造函数,实例原型的constructor 属性也指向构造函数
function Person() {
}
let person = new Person();
console.log(person.__proto__ === Person.prototype);
console.log(person.__proto__.constructor===Person);
console.log(Person.prototype.constructor===Person);
//注意原型是一个对象,所以要通过__proto__指向自己的原型
console.log(Person.prototype.__proto__=== Object.prototype);
//true
//true
//true
//true
在Javascript中,每个函数都有一个原型属性prototype指向自身的原型,而由这个函数创建的对象也有一个__proto__属性指向这个原型,而函数的原型是一个对象,所以这个对象也会有一个__proto__指向自己的原型,这样逐层深入直到Object对象的原型,这样就形成了原型链。普通对象没有prototype,但有__proto__属性。
2.函数拥有多个原型
函数拥有多个原型(可以有多个父亲),在prototype 上定义的用于实例对象使用,在__proto__上定义的用于函数对象使用
function User() {}
User.__proto__.view = function() {
console.log("User function view method");
};
User.view();
User.prototype.show = function() {
console.log("show you something");
};
let hd = new User();
hd.show();
//User function view method
//show you something
3.设置原型
使用Object.setPrototypeOf可设置对象的原型
虽然可以通过以下设置原型
let hd = {
name: "hd"
};
let parent = {
name: "parent",
show() {
console.log("parent method: " + this.name);
}
}hd.__proto__ = parent
但这不是官方手段,不建议使用这种方法
let hd = {
name: "hd"
};
let parent = {
name: "parent",
show() {
console.log("parent method: " + this.name);
}
}
//让hd继承parent,即设置hd的原型为parent
Object.setPrototypeOf(hd, parent);
hd.show();
parent.show();
//parent method: hd
//parent method: parent
注意:哪个对象调用函数,函数中的this就指向哪个对象。
4.__proto__是属性访问器
let xj = {};
xj.__proto__ = "demo";
console.log(xj);
打印输出上面的结果如图所示:
发现修改对象的__proto__是不会成功的,因为其内部使用getter/setter访问器来控制值,所以修改对象的__proto__的值只允许对象或null,这也是为什么不建议直接修改对象的__proto__的值来更改原型
下面定义的__proto__ 就会成功,因为这是一个极简对象,没有原型对象所以不会影响__proto__ 赋值。
let hd = Object.create(null);
hd.__proto__ = "demo";
console.log(hd);
//{__proto__: "demo"}