Cognition of the prototype chain

1. The concept of prototype chain

The prototype chain , as the name suggests, is actually a chain composed of prototypes and is composed of the implicit prototype __proto__ , which is used to access and find the attributes of an object .

From the previous article, you can know that any function has an attribute prototype (explicit prototype), and any instance object also has an implicit prototype __proto__, and the implicit prototype of the instance object is equivalent to the explicit prototype of its constructor . However, through printing, we found that there is also an implicit prototype in the prototype object of the constructor. This shows that the prototype object of the constructor is an instance object . So whose instance is it? Is an instance of the Object object .

Prototype chain , alias is the implicit prototype chain . When accessing the properties of an object , first search in its own properties , and return if found. If not, then search upward along the __proto__ chain , and return if found. If it is not found in the end , return undefined.

The role of the prototype chain: find the properties (methods) of the object.

1.1 Code experience

// 注意方法也是属性
<script>
    // 1. 创建一个构造函数,并为其实例添加属性test1
    function Fn() {
        this.test1 = function() {
            console.log('test1()');
        }
    };
    // 2. 为其显式原型添加属性test2
    Fn.prototype.test2 = function() {
        console.log('test2()');
    };
    // 3. 创建一个实例对象fn
    let fn = new Fn();
    // 4. 实例可以调用test1、test2、toString,但是无法调用test3
    fn.test1();
    fn.test2();
    console.log(fn.toString());
    fn.test3();
</script>

analyze:

① fn can call the test1 attribute because this is its own attribute ;

② fn can call the test2 attribute because it is found through its own __proto__ attribute . (The __proto__ attribute of the instance has the same address as the prototype of its constructor, pointing to the same Object instance object. The above code adds the attribute test2 to it through the prototype of the constructor, so it can be called

③ fn can call the toString attribute because the __proto__ attribute in the Object instance object pointed to by the __proto__ attribute points to the prototype object of the Object object , and the attribute is stored in the prototype object.

④ fn cannot call the test3 attribute because it is searched all the way until the prototype object prototype in the Object object is not found.

The process of calling attributes by fn above is a prototype chain, looking up layer by layer through __proto__.

<script>
    function Fn() {

    };
    //  1. 函数的显示原型指向的对象:默认是空Object的实例对象(但Object本身不满足这一说法)
    // instanceof作用:测试它左边的对象是否是它右边的类的实例
    console.log(Fn.prototype instanceof Object); // true
    console.log(Object.prototype instanceof Object); // false
    console.log(Function.prototype instanceof Object); // true
    //  2. 所有函数都是Function的实例(包含Function本身)
    //  说明所有函数的__proto__都是一样的
    function Fun(){};    // 等同于  let Fun=new Function();
    // 这就说明函数Fun是Function的实例
    Function=new Function();  // 这说明Function本身也是Function的实例
    console.log(Function.__proto__ === Function.prototype); // true,构造函数Function的原型对象===实例的隐式原型,证明上述结论的准确性
    //  3. Object的原型对象是原型链尽头
    console.log(Object.prototype.__proto__); // null
</script>

Since the value of the __proto__ attribute in the prototype object of Object is null , the prototype object of Object is the end of the prototype chain , that is, searching from bottom to top until the attribute is not found in the prototype object of Object, then is undefined.

1.2 Prototype chain diagram

2.Prototype chain attribute issues

①   When reading the attribute value of the object : it will automatically search in the prototype chain ;
②  When setting the attribute value of the object : it will not search the prototype chain . If there is no such attribute in the current object, directly add this attribute and set its value;
③  Method Properties are generally defined in the prototype , and properties are generally defined on the instance object itself through the constructor ;

<script>
    // 1. 定义一个构造函数
    function Fn() {

    };
    // 2. 为原型对象添加属性a
    Fn.prototype.a = '你好吗?';
    // 3. 创建一个实例对象 fn1
    let fn1 = new Fn();
    // 读取属性时会自动到原型链中查找
    console.log(fn1.a); // 你好吗?
    // 4. 创建一个实例对象 fn2
    let fn2 = new Fn();
    // 5. 为fn2 实例对象设置属性a,该属性是fn2实例对象的专有属性,所以fn1无法获取
    // 设置对象的属性值时,不会查找原型链,而是只看当前对象本身是否存在该属性,如果没有则直接添加并设置值,如果有则覆盖之前的值
    fn2.a = '我很好';
    console.log(fn1.a, fn1); // 你好吗?
    console.log(fn2.a, fn2); // 我很好

    // 6.1 属性一般通过构造函数直接定义在实例对象本身上
    function Person(name, age) {
        this.name = name;
        this.age = age;
    };
    // 6.2 方法一般定义在构造函数的原型中
    Person.prototype.setName = function(name) {
        this.name = name;
    };
    // 6.3 正因为这样的设置,每个实例对象都拥有了自身的属性,但是方法均来源于原型中
    let p1 = new Person('张三', 22);
    p1.setName('Tom');
    console.log(p1);

    let p2 = new Person('李四', 35);
    p2.setName('Bob');
    console.log(p2);
    // 同一构造函数中所有实例对象的隐式原型都是指向该函数的显式原型prototype,所以相等
    console.log(p1.__proto__ === p2.__proto__);  // true
</script>

3. Relationship between constructor/prototype/instance object

 

From the above figure, we can know that any function is an instance object of the constructor Function , that is, all functions have an implicit prototype __proto__, which points to the displayed prototype prototype of the Function. But note: Function is a built-in constructor and an object. It inherits all properties and methods of Object , so the __proto__ of Function's prototype object points to the prototype prototype of Object.

 

Guess you like

Origin blog.csdn.net/JJ_Smilewang/article/details/125686492