The prototype attribute of the function (prototype object)

1.Prototype attribute of function

Each function has a prototype attribute , which by default is an empty Object instance object (that is, called the prototype object ), and the prototype object has an attribute constructor , which points to the function object . This means that the (constructor) function and its prototype object refer to each other .

Type represents the constructor, which has an attribute prototype, and this attribute points to the prototype object of this function, and this object has an attribute constructor, which points back to the constructor Type, that is, a mutual reference relationship.

1.1 Code experience

<script>
    // 1. 每个函数都有一个prototype属性,它默认指向一个Object空对象(即称为:原型对象)
    // (1) 内置对象(构造函数)
    // 打印结果是object,但不是空对象,原因是系统内部先前已为其添加了各种属性,但它本身原始是空对象
    console.log(Date.prototype);
    // (2) 自定义对象(构造函数)
    function Fun() {

    };
    console.log(Fun.prototype); // 默认指向Object的空实例对象(没有程序员自己指定的属性)
    // 2. 原型对象中有一个属性constructor(默认内置的属性),它指向函数对象
    console.log(Date.prototype.constructor === Date); // true
    console.log(Fun.prototype.constructor === Fun);   //true
</script>

Note: Any function has a prototype attribute , but we usually only mention using it when using the constructor. Don't misunderstand it.

2. Explicit prototypes and implicit prototypes

①  Each function has a prototype , that is, an explicit prototype
②  Each instance object has a __proto__ , which can be called an implicit prototype
③ The value of the implicit prototype of the object is the value of the explicit prototype of the corresponding constructor (explicit prototype formula prototype === implicit prototype)

2.1 Code experience

<script>
    // 1. 定义构造函数
    function Fn() {  // 内部执行语句:this.prototype={}

    };
    // (1)每个函数function都有一个prototype,即显式原型属性,默认指向一个空的object对象
    console.log(Fn.prototype);
    // 2. 创建一个实例对象
    let fn = new Fn();   // 内部执行语句:this.__proto__ = Fn.prototype
    // (2)每个实例对象都有一个__proto__,即隐式原型属性
    console.log(fn.__proto__);
    // (3)对象的隐式原型的值为其对应的构造函数的显式原型的值
    console.log(fn.__proto__ === Fn.prototype);  // true
    // 3. 给显式原型(原型对象) 添加属性(一般是方法)
    Fn.prototype.test = function() {
        console.log('test()');
    };
    // 4. 通过实例对象可调用原型对象的方法
    fn.test();  // 打印结果 test()
</script>

Summarize:

① The prototype attribute of the function: automatically added when defining the function. The default value is an empty Object instance.

② The __proto__ attribute of the object: automatically added when the object is created. The default value is the prototype attribute value of the constructor.

③ Programmers can directly operate explicit prototypes (add attributes (usually methods) ==> instance objects are accessible), but generally do not directly operate implicit prototypes.

2.2 Memory structure diagram

In order to easily understand prototypes and the difference between explicit and implicit prototypes, you can combine the following pictures to enhance your understanding.

 3. Handwritten array function

After understanding the relevant knowledge of prototypes, we can use our own handwritten functions to encapsulate the same functions for some of the array methods we learned earlier, so as to better understand the concept and use of prototypes.

<script>
    // 给内置构造函数Array的原型对象上添加自己书写的方法,这样使用数组时就可以调用该方法了
    // (1) 过滤方法
    Array.prototype.myFilter = function(callback) {
        let narr = [];
        for (let i = 0; i < this.length; i++) {
            if (callback(this[i])) {
                narr.push(this[i])
            }
        }
        return narr;
    };
    // (2) 映射方法
    Array.prototype.myMap = function(callback) {
        let narr = [];
        for (let i = 0; i < this.length; i++) {
            narr.push(callback(this[i]));
            callback()
        };
        return narr;
    };
    // (3) 累计方法
    // num表示初始值
    Array.prototype.myReduce = function(callback, num) {
        // sum表示计算结束后的返回值。
        let sum = num;
        for (let i = 0; i < this.length; i++) {
            sum = callback(sum, this[i])
        };
        return sum
    }
    let arr1 = [11, 22, 33, 44, 55, 66, 77, 88, 99, 123, 456];
    // 由于上面我给内置对象Array的原型对象上添加了3个新方法,所以下面的实例对象就可以直接使用
    let arr2 = arr1.myFilter(r => r % 2 === 0);  // 从原数组中过滤出一个只含奇数的新数组
    console.log(arr2);
    let arr3 = arr1.myMap(r => r + 1);  // 从原数组中映射出一个各元素的值均大1的新数组
    console.log(arr3);
    let arr4 = arr1.myReduce((a, b) => {  // 将原数组各元素的值累加为一个值(即求和)
        return a + b
    }, 0);
    console.log(arr4);  // 1074
</script>

4. Practical applications

Because we programmers can manually add attributes (methods) to the function's prototype object, in actual development, when creating a constructor, if we need to create a large number of instantiated objects, then add the method to the function's prototype object prototype . This reduces memory space, greatly improving performance

<script>
    function Student(name, age, sex) {
        // 给构造函数添加属性,要使用this,这个this是指向实例化对象的
        // 普通属性我们可以直接添加即可,属性值以形参的形式传入,这样具有扩展性
        this.name = name
        this.age = age
        this.sex = sex
    };
    // 方法不直接添加,而是将其添加在函数的原型对象上,这样函数的所有实例对象自动拥有原型中的方法, 
    // 从而可以减少内存空间,从而提高性能
    Student.prototype.sayHi = function() {
        console.log(`我叫${this.name},今年${this.age}岁,性别是${this.sex}`);
    };
    Student.prototype.study = function(time) {
        console.log(`我叫${this.name},我每天学习${time}小时`);
    };
    // 创建多个实例化对象时,直接使用原型方法,并且因为使用了this指向,所以打印的内容都是活泛的
    let s1 = new Student("张三", 22, "男");
    s1.sayHi();
    s1.study(10);
    let s2 = new Student("李四", 34, "男");
    s2.sayHi();
    s1.study(8);
    let s3 = new Student("王燕", 29, "女");
    s3.sayHi();
    s3.study(12);
</script>

Guess you like

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