Home >Web Front-end >JS Tutorial >Comprehensive analysis of this, constructor, prototype of js cliché_javascript skills

Comprehensive analysis of this, constructor, prototype of js cliché_javascript skills

WBOY
WBOYOriginal
2016-05-16 15:06:291493browse

Foreword

This, constructor, and prototype in JavaScript are all commonplace issues, and it is crucial to understand their meaning in depth. Here, let’s review it again, review the past and learn the new!

this

This represents the current object. If this is used in the global scope, it refers to the current page object window; if this is used in a function, what this refers to is based on the object on which this function is called at runtime. We can also use the two global methods apply and call to change the specific pointer of this in the function.

Let’s first look at an example of using this in the global scope:

console.log(this === window); // true
console.log(window.alert === this.alert); // true
console.log(this.parseInt("021", 10)); // 10

This in the function is determined at runtime, not when the function is defined, as follows:

// 定义一个全局函数
    function foo() {
      console.log(this.fruit);
    }
    // 定义一个全局变量,等价于window.fruit = "apple";
    var fruit = "apple";
    // 此时函数foo中this指向window对象
    // 这种调用方式和window.foo();是完全等价的
    foo(); // "apple"

    // 自定义一个对象,并将此对象的属性foo指向全局函数foo
    var pack = {
      fruit: "orange",
      foo: foo
    };
    // 此时函数foo中this指向window.pack对象
    pack.foo(); // "orange"

The global functions apply and call can be used to change the pointer of this in the function, as follows:

// 定义一个全局函数
    function foo() {
      console.log(this.fruit);
    }

    // 定义一个全局变量
    var fruit = "apple";
    // 自定义一个对象
    var pack = {
      fruit: "orange"
    };

    // 等价于window.foo();
    foo.apply(window); // "apple"
    // 此时foo中的this === pack
    foo.apply(pack);  // "orange"

Note: The apply and call functions have the same function. The only difference is that the parameter definitions of the two functions are different.

Because functions are also objects in JavaScript, we can see the following interesting examples:

// 定义一个全局函数
    function foo() {
      if (this === window) {
        console.log("this is window.");
      }
    }

    // 函数foo也是对象,所以可以定义foo的属性boo为一个函数
    foo.boo = function() {
      if (this === foo) {
        console.log("this is foo.");
      } else if (this === window) {
        console.log("this is window.");
      }
    };
    // 等价于window.foo();
    foo(); // this is window.

    // 可以看到函数中this的指向调用函数的对象
    foo.boo(); // this is foo.

    // 使用apply改变函数中this的指向
    foo.boo.apply(window); // this is window.

prototype

Prototype is essentially a JavaScript object.

And each function has a default prototype attribute. If this function is used in the context of creating a custom object, we call this function a constructor. For example, the following simple scene:

// 构造函数
    function Person(name) {
      this.name = name;
    }
    // 定义Person的原型,原型中的属性可以被自定义对象引用
    Person.prototype = {
      getName: function() {
        return this.name;
      }
    }
    var hao= new Person("haorooms");
    console.log(hao.getName());  // "haorooms"

As an analogy, let’s consider the data types in JavaScript - String, Number, Array, Object, Date, etc.

We have reason to believe that these types are implemented as constructors inside JavaScript, such as:

// 定义数组的构造函数,作为JavaScript的一种预定义类型
    function Array() {
      // ...
    }

    // 初始化数组的实例
    var arr1 = new Array(1, 56, 34, 12);
    // 但是,我们更倾向于如下的语法定义:
    var arr2 = [1, 56, 34, 12];

At the same time, many methods of operating on arrays (such as concat, join, push) should also be defined in the prototype attribute. In fact, all JavaScript intrinsic data types have a read-only prototype attribute (this is understandable: if you modify the prototype attribute of these types, the predefined methods disappear), but we can add to it own extension method.

// 向JavaScript固有类型Array扩展一个获取最小值的方法
    Array.prototype.min = function() {
      var min = this[0];
      for (var i = 1; i < this.length; i++) {
        if (this[i] < min) {
          min = this[i];
        }
      }
      return min;
    };

    // 在任意Array的实例上调用min方法
    console.log([1, 56, 34, 12].min()); // 1

Note: There is a trap here. After adding an extension method to the prototype of Array, this extension method will also be looped out when using for-in to loop the array. The following code illustrates this (assuming that the min method has been extended to the Array prototype):

var arr = [1, 56, 34, 12];
    var total = 0;
    for (var i in arr) {
      total += parseInt(arr[i], 10);
    }
    console.log(total);  // NaN

The solution is also very simple:

var arr = [1, 56, 34, 12];
    var total = 0;
    for (var i in arr) {
      if (arr.hasOwnProperty(i)) {
        total += parseInt(arr[i], 10);
      }
    }
    console.log(total);  // 103

constructor

constructor always points to the constructor that created the current object. For example, the following example:

// 等价于 var foo = new Array(1, 56, 34, 12);
    var arr = [1, 56, 34, 12];
    console.log(arr.constructor === Array); // true
    // 等价于 var foo = new Function();
    var Foo = function() { };
    console.log(Foo.constructor === Function); // true
    // 由构造函数实例化一个obj对象
    var obj = new Foo();
    console.log(obj.constructor === Foo); // true

    // 将上面两段代码合起来,就得到下面的结论
    console.log(obj.constructor.constructor === Function); // true

But when the constructor encounters the prototype, something interesting happens. We know that each function has a default attribute prototype, and the constructor of this prototype points to this function by default. As shown in the following example:

function Person(name) {
      this.name = name;
    };
    Person.prototype.getName = function() {
      return this.name;
    };
    var p = new Person("haorooms");

    console.log(p.constructor === Person); // true
    console.log(Person.prototype.constructor === Person); // true
    // 将上两行代码合并就得到如下结果
    console.log(p.constructor.prototype.constructor === Person); // true

When we redefined the prototype of the function (note: the difference from the above example, this is not a modification but an override), the behavior of the constructor was a bit strange, as shown in the following example:

function Person(name) {
      this.name = name;
    };
    Person.prototype = {
      getName: function() {
        return this.name;
      }
    };
    var p = new Person("haorooms");
    console.log(p.constructor === Person); // false
    console.log(Person.prototype.constructor === Person); // false
    console.log(p.constructor.prototype.constructor === Person); // false

Why? It turns out that when overriding Person.prototype, it is equivalent to performing the following code operation:

Person.prototype = new Object({
      getName: function() {
        return this.name;
      }
    });

The constructor always points to the constructor that creates itself, so at this time Person.prototype.constructor === Object, that is:

function Person(name) {
      this.name = name;
    };
    Person.prototype = {
      getName: function() {
        return this.name;
      }
    };
    var p = new Person("haorooms");
    console.log(p.constructor === Object); // true
    console.log(Person.prototype.constructor === Object); // true
    console.log(p.constructor.prototype.constructor === Object); // true

How to fix this problem? The method is also very simple, just override Person.prototype.constructor:

function Person(name) {
      this.name = name;
    };
    Person.prototype = {
      getName: function() {
        return this.name;
      }
    };
    Person.prototype.constructor = Person;
    var p = new Person("haorooms");
    console.log(p.constructor === Person); // true
    console.log(Person.prototype.constructor === Person); // true
    console.log(p.constructor.prototype.constructor === Person); // true

can also be written like this:

function Person(name) {
      this.name = name;
    };
    Person.prototype = {
     constructor:Person,//指定constructor
      getName: function() {
        return this.name;
      }
    };

The above comprehensive analysis of this, constructor, and prototype of js clichés is all the content shared by the editor. I hope it can give you a reference, and I also hope that everyone will support Script Home.

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn