>웹 프론트엔드 >JS 튜토리얼 >이에 대한 종합 분석, js cliché_javascript 스킬의 생성자, 프로토타입

이에 대한 종합 분석, js cliché_javascript 스킬의 생성자, 프로토타입

WBOY
WBOY원래의
2016-05-16 15:06:291496검색

머리말

자바스크립트에서 이, 생성자, 프로토타입은 모두 흔한 문제이며, 그 의미를 깊이 이해하는 것이 중요합니다. 여기서 다시 복습하고, 과거를 복습하고, 새로운 것을 배워봅시다!

이것

현재 개체를 나타냅니다. 전역 범위에서 사용되는 경우 현재 페이지 개체 창을 참조하고, 함수에서 사용되는 경우 참조하는 것은 이 함수가 호출되는 개체에 따라 결정됩니다. 런타임에. 또한 함수에서 this의 특정 포인터를 변경하기 위해 apply와 call이라는 두 가지 전역 메서드를 사용할 수도 있습니다.

먼저 전역 범위에서 이를 사용하는 예를 살펴보겠습니다.

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

함수에서 이는 다음과 같이 함수가 정의될 ​​때가 아니라 런타임에 결정됩니다.

// 定义一个全局函数
    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"

전역 함수 apply 및 call을 사용하여 함수에서 this의 포인터를 다음과 같이 변경할 수 있습니다.

// 定义一个全局函数
    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"

참고: 적용 및 호출 함수는 동일한 기능을 가지고 있습니다. 유일한 차이점은 두 함수의 매개변수 정의가 다르다는 것입니다.

함수도 JavaScript의 객체이기 때문에 다음과 같은 흥미로운 예를 볼 수 있습니다.

// 定义一个全局函数
    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.

시제품

프로토타입은 기본적으로 JavaScript 개체입니다.

그리고 각 함수에는 기본 프로토타입 속성이 있습니다. 이 함수가 사용자 정의 객체를 생성하는 맥락에서 사용되는 경우 이 함수를 생성자라고 부릅니다. 예를 들어 다음과 같은 간단한 장면이 있습니다.

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

비유적으로 JavaScript의 데이터 유형(문자열, 숫자, 배열, 객체, 날짜 등)을 고려해 보겠습니다.

이러한 유형은 다음과 같이 JavaScript 내부의 생성자로 구현된다고 믿을 만한 이유가 있습니다.

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

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

동시에 배열에 대한 다양한 작업 방법(예: 연결, 조인, 푸시)도 프로토타입 속성에 정의되어야 합니다. 실제로 모든 JavaScript 내장 데이터 유형에는 읽기 전용 프로토타입 속성이 있지만(이해할 수 있습니다. 이러한 유형의 프로토타입 속성을 수정하면 미리 정의된 메서드가 사라집니다), 자체 확장 메서드를 추가할 수 있습니다.

// 向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

참고: 여기에는 함정이 있습니다. 배열의 프로토타입에 확장 메서드를 추가한 후 for-in을 사용하여 배열을 반복할 때 이 확장 메서드도 반복됩니다. 다음 코드는 이를 보여줍니다(min 메소드가 Array 프로토타입으로 확장되었다고 가정).

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

해결책도 매우 간단합니다.

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

생성자

생성자는 항상 현재 객체를 생성한 생성자를 가리킵니다. 예를 들면 다음과 같습니다.

// 等价于 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

그러나 생성자가 프로토타입을 만나면 흥미로운 일이 발생합니다. 우리는 각 함수에 기본 속성 프로토타입이 있고 이 프로토타입의 생성자가 기본적으로 이 함수를 가리킨다는 것을 알고 있습니다. 다음 예에 표시된 대로:

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

함수의 프로토타입을 재정의했을 때(참고: 위 예와의 차이점은 수정이 아니라 재정의임) 다음 예에서 볼 수 있듯이 생성자의 동작이 약간 이상했습니다.

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

왜요? Person.prototype을 재정의하면 다음 코드 작업을 수행하는 것과 같습니다.

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

생성자는 항상 자신을 생성하는 생성자를 가리키므로 이때 Person.prototype.constructor === Object, 즉

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

이 문제를 해결하는 방법은 무엇입니까? 이 방법도 매우 간단합니다. 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

다음과 같이 쓸 수도 있습니다:

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

위의 종합적인 분석과 js 클리셰의 생성자, 프로토타입은 모두 편집자가 공유한 내용이므로 참고가 되셨으면 좋겠습니다. 또한 모두가 Script Home을 응원해 주시길 바랍니다.

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.