一些原型的理解(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"}
posted @ 2021-02-06 21:51  Hhhighway  阅读(59)  评论(0编辑  收藏  举报