Typescript 프로토 타입 객체 프로토 타입 심층 이해

Typescript 프로토 타입 객체 프로토 타입



머리말

이 기사에서는 주로 Typescript의 프로토 타입 객체 프로토 타입과 프로토 타입 객체를 얻는 방법에 대해 설명합니다.


팁 : 다음은이 기사의 내용이며 다음 사례는 참고 용입니다.

1. 프로토 타입이란?

JavaScript에서 프로토 타입 객체는 객체 지향을위한 중요한 메커니즘입니다. 각 함수는 객체 (Function)이고, 함수 객체에는 하위 객체 프로토 타입 객체가 있으며, 클래스는 함수 형태로 정의됩니다. Prototype은 함수의 프로토 타입을 나타내며 클래스 멤버 컬렉션을 나타냅니다. 자바 스크립트에서 상속과 관련하여 자바 스크립트는 오직 하나의 구조, 즉 객체 만 가지고 있습니다. class 키워드는 ES2015 / ES6에서 도입되었지만 이는 단지 구문 적 설탕이며 JavaScript는 여전히 프로토 타입 기반입니다.

1. 객체 인스턴스의 __proto__ 속성

각 인스턴스 객체 (객체)에는 생성자의 프로토 타입 객체를 가리키는 전용 속성 (__proto__)이 있습니다. 프로토 타입 객체는 또한 객체의 프로토 타입 객체가 null이 될 때까지 레이어별로 자체 프로토 타입 객체 (__proto__)를 갖습니다. 정의에 따라 null은 프로토 타입이 없으며 프로토 타입 체인의 마지막 링크 역할을합니다.

2. Object.getPrototypeOf ()는 객체 인스턴스의 __proto__ 속성을 가져옵니다.

ECMAScript 표준에 따라 someObject .__ proto__ 기호는 someObject의 프로토 타입 객체 프로토 타입을 가리키는 데 사용됩니다. ECMAScript 6부터 __proto__는 Object.getPrototypeOf () 및 Object.setPrototypeOf () 접근자를 통해 액세스 할 수 있습니다. 이는 많은 브라우저에서 구현하는 비표준 JavaScript 속성 __proto__와 동일합니다. 그러나 생성자 Function의 프로토 타입 속성과 혼동해서는 안됩니다. 생성자가 생성 한 인스턴스 객체의 __proto__는 Function의 프로토 타입 속성을 가리 킵니다. Object.prototype 속성은 Object의 프로토 타입 객체를 나타냅니다.

3. 예

다음 예제는 dog 인스턴스의 프로토 타입 체인을 보여줍니다 : 즉
dog–> Animal.prototype –> Object.prototype –> null
인스턴스 객체 dog의 프로토 타입 객체 __proto__는 생성자 함수 Animal의 프로토 타입 속성을 참조하고 prototype 내부 속성 __proto_도있는 객체이므로 생성자 Object의 프로토 타입 속성을 가리 킵니다. 모든 속성, 메서드 및 동작은 개체의 프로토 타입 개체가 null이 될 때까지 계층별로 올라갑니다.

class Animal {
    
    
    name:string;
    constructor(name:string="Animal") {
    
    
      this.name = name;  
    }
    sayHello(){
    
    
        console.log("Hello ",this.name);
    }
}
console.log(typeof(Animal.prototype)) // object

let dog = new Animal("Dog")
console.log(Object.getPrototypeOf(dog) === Animal.prototype) // true
console.log(Object.getPrototypeOf(Animal.prototype) === Object.prototype) // true
console.log(Object.getPrototypeOf(Object.prototype) === null) // true

2. 프로토 타입에 대한 심층적 이해

1. 기능 개체

함수 선언 (함수)에 의해 생성 된 각 함수는 Function 객체의 모든 속성, 메서드 및 동작이있는 Function 객체입니다. 함수 선언 파일을 살펴보면 먼저 FunctionConstructor 유형의 객체 유형 인터페이스로 정의되며, 여기에는 두 개의 메소드가 포함되어 있으며 둘 다 함수 유형이라는 객체 유형 인터페이스와 읽기 전용 프로토 타입 함수 객체 유형 인터페이스 속성을 반환합니다.

interface FunctionConstructor {
    
    
    /**
     * Creates a new function.
     * @param args A list of arguments the function accepts.
     */
    new(...args: string[]): Function;
    (...args: string[]): Function;
    readonly prototype: Function;
}

declare var Function: FunctionConstructor;

2. 기능. 프로토 타입

Function.prototype 또는 FunctionConstructor.prototype은 Function 객체 유형 인터페이스이고 Function 객체 유형 인터페이스도 객체 객체입니다. JavaScript의 거의 모든 객체는 프로토 타입 체인의 맨 위에있는 Object의 인스턴스입니다. 각 개체 개체는 생성자 함수를 정의합니다.

interface Object {
    
    
    /** The initial value of Object.prototype.constructor is the standard built-in Object constructor. */
    constructor: Function;
    ...
}
/**
 * Creates a new function.
 */
interface Function {
    
    
    /**
     * Calls the function, substituting the specified object for the this value of the function, and the specified array for the arguments of the function.
     * @param thisArg The object to be used as the this object.
     * @param argArray A set of arguments to be passed to the function.
     */
    apply(this: Function, thisArg: any, argArray?: any): any;

    /**
     * Calls a method of an object, substituting another object for the current object.
     * @param thisArg The object to be used as the current object.
     * @param argArray A list of arguments to be passed to the method.
     */
    call(this: Function, thisArg: any, ...argArray: any[]): any;

    /**
     * For a given function, creates a bound function that has the same body as the original function.
     * The this object of the bound function is associated with the specified object, and has the specified initial parameters.
     * @param thisArg An object to which the this keyword can refer inside the new function.
     * @param argArray A list of arguments to be passed to the new function.
     */
    bind(this: Function, thisArg: any, ...argArray: any[]): any;

    /** Returns a string representation of a function. */
    toString(): string;

    prototype: any;
    readonly length: number;

    // Non-standard extensions
    arguments: any;
    caller: Function;
}

3. 예

다음 예제는 Animal 함수의 프로토 타입 체인을 보여줍니다.
Animal-> Function.prototype –> Object.prototype –> null
인스턴스 메소드 Animal의 프로토 타입 객체 __proto__는 생성자 Function의 프로토 타입 속성을 참조하고 prototype은 또한 The 따라서 내부 속성 __proto_는 생성자 Object의 프로토 타입 속성을 가리 킵니다.

class Animal {
    
    
    name:string;
    constructor(name:string="Animal") {
    
    
      this.name = name;  
    }
    sayHello(){
    
    
        console.log("Hello ",this.name);
    }
}

console.log(typeof Animal); // function
console.log(Object.getPrototypeOf(Animal) === Function.prototype) // true
console.log(Object.getPrototypeOf(Function.prototype) === Object.prototype) // true
console.log(Object.getPrototypeOf(Object.prototype) === null) // true

4. 프로토 타입과 Object.getPrototypeOf ()의 차이점

Animal 함수에 prototype이라는 특수 속성이 있음을 알 수 있습니다. 이 특수 속성은 JavaScript의 new 연산자와 함께 사용할 수 있습니다. 프로토 타입 객체에 대한 참조는 새 인스턴스의 내부 __proto__ 속성에 복사됩니다. 예를 들어, var animal = new Animal ();이 실행되면 JavaScript (메모리에 객체를 만든 후 객체를 가리 키도록 Animal () 함수를 실행하기 전)는 animal .__ proto__ = Animal.prototype;을 설정합니다. 그런 다음 인스턴스의 속성에 액세스 할 때 JavaScript는 먼저 개체에 직접 존재하는지 확인하고 존재하지 않으면 __proto__에서 찾습니다. 즉, 프로토 타입에 정의한 모든 내용을 모든 인스턴스에서 효과적으로 공유 할 수 있으며 나중에 프로토 타입의 일부를 변경하고 필요한 경우 모든 기존 인스턴스의 변경 사항을 표시 할 수도 있습니다.

위의 예에서와 같이 var a1 = new Animal (); var a2 = new Animal ();을 실행하면 a1.sayHello ()가 실제로 Object.getPrototypeOf (a1) .sayHello ()를 가리 킵니다. Animal.prototype.sayHello에 정의 된 내용입니다. 즉, Object.getPrototypeOf (a1) .sayHello == Object.getPrototypeOf (a2) .sayHello == Animal.prototype.sayHello (보충 : 실제로 a1.sayHello ()를 실행하는 것은 Object.getPrototypeOf (a1)를 실행하는 것과 같습니다. ) .sayHello.call (a1) == Animal.prototype.sayHello.call (a1))

요컨대 프로토 타입은 클래스에 사용되고 Object.getPrototypeOf ()는 인스턴스 (인스턴스)에 사용되며 둘 다 동일한 기능을 갖습니다.

3. 프로토 타입 체인의 역할

상속하다

ES5 상속에서 본질은 먼저 하위 클래스의 this 인스턴스 개체를 만든 다음 부모 클래스의 메서드를 여기에 추가하는 것입니다 (Parent.apply (this)). ES6의 상속 메커니즘은 완전히 다릅니다. 본질은 먼저 부모 클래스의 인스턴스 객체의 속성과 메서드를 여기에 추가 한 다음 (수퍼 메서드를 먼저 호출해야 함) 하위 클래스의 생성자를 사용하여 수정하는 것입니다. 이.

class Parent {
    
    }

class Child extends Parent {
    
    
  constructor() {
    
    
    super();
  }
}

super는 부모 클래스 Parent의 생성자를 나타내지 만 자식 클래스 Child의 인스턴스를 반환합니다. 즉, 내부 super는 Child의 인스턴스를 참조하므로 super ()는 Parent.prototype.constructor.call과 동일합니다. (이). 자식 클래스 Child의 생성자에있는 super ()는 부모 클래스의 생성자 호출을 나타냅니다. 이것은 필요합니다. 그렇지 않으면 JavaScript 엔진이 오류를보고합니다.

프로토 타입 체인 아이콘 :
여기에 사진 설명 삽입

1. 재산 상속

자바 스크립트 객체는 동적 속성 "가방"(자체 속성을 나타냄)입니다. JavaScript 객체에는 프로토 타입 객체에 대한 링크가 있습니다. 객체의 속성에 액세스하려고 할 때 객체를 검색 할뿐만 아니라 객체의 프로토 타입과 객체의 프로토 타입을 검색하여 일치하는 이름의 속성을 찾거나 프로토 타입에 도달 할 때까지 연속적으로 위쪽으로 검색합니다. 체인의 끝.

	// 让我们从一个函数里创建一个对象o,它自身拥有属性a和b的:
	let f = function () {
    
    
	   this.a = 1;
	   this.b = 2;
	}
	/* 这么写也一样
	function f() {
	  this.a = 1;
	  this.b = 2;
	}
	*/
	let o = new f(); // {a: 1, b: 2}
	
	// 在f函数的原型上定义属性
	f.prototype.b = 3;
	f.prototype.c = 4;
	
	// 不要在 f 函数的原型上直接定义 f.prototype = {b:3,c:4};这样会直接打破原型链
	// o.[[Prototype]] 有属性 b 和 c
	//  (其实就是 o.__proto__ 或者 o.constructor.prototype)
	// o.[[Prototype]].[[Prototype]] 是 Object.prototype.
	// 最后o.[[Prototype]].[[Prototype]].[[Prototype]]是null
	// 这就是原型链的末尾,即 null,
	// 根据定义,null 就是没有 [[Prototype]]。
	
	// 综上,整个原型链如下:
	
	// {a:1, b:2} ---> {b:3, c:4} ---> Object.prototype---> null
	
	console.log(o.a); // 1
	// a是o的自身属性吗?是的,该属性的值为 1
	
	console.log(o.b); // 2
	// b是o的自身属性吗?是的,该属性的值为 2
	// 原型上也有一个'b'属性,但是它不会被访问到。
	// 这种情况被称为"属性遮蔽 (property shadowing)"
	
	console.log(o.c); // 4
	// c是o的自身属性吗?不是,那看看它的原型上有没有
	// c是o.[[Prototype]]的属性吗?是的,该属性的值为 4
	
	console.log(o.d); // undefined
	// d 是 o 的自身属性吗?不是,那看看它的原型上有没有
	// d 是 o.[[Prototype]] 的属性吗?不是,那看看它的原型上有没有
	// o.[[Prototype]].[[Prototype]] 为 null,停止搜索
	// 找不到 d 属性,返回 undefined

2. 메서드 상속

JavaScript에는 다른 클래스 기반 언어로 정의 된 "메서드"가 없습니다. JavaScript에서는 모든 함수를 객체의 속성으로 객체에 추가 할 수 있습니다. 함수 상속은 위의 "속성 마스킹"을 포함하여 다른 속성 상속과 다르지 않습니다 (이 상황은 다른 언어로 메서드 재 작성과 동일 함).

	var o = {
    
    
	  a: 2,
	  m: function(){
    
    
	    return this.a + 1;
	  }
	};
	
	console.log(o.m()); // 3
	// 当调用 o.m 时,'this' 指向了 o.
	
	var p = Object.create(o);
	// p是一个继承自 o 的对象
	
	p.a = 4; // 创建 p 的自身属性 'a'
	console.log(p.m()); // 5
	// 调用 p.m 时,'this' 指向了 p
	// 又因为 p 继承了 o 的 m 函数
	// 所以,此时的 'this.a' 即 p.a,就是 p 的自身属性 'a' 

넷째, 프로토 타입 체인의 성능

프로토 타입 체인에서 속성을 찾는 것은 시간이 많이 걸리고 성능에 부작용이 있으며 이는 까다로운 성능 요구 사항에서 매우 중요합니다. 또한 존재하지 않는 속성에 액세스하려고하면 전체 프로토 타입 체인을 통과하게됩니다.
객체의 속성을 탐색 할 때 프로토 타입 체인의 모든 열거 가능한 속성이 열거됩니다. 개체에 프로토 타입 체인의 속성이 아닌 자체 정의 된 속성이 있는지 확인하려면 모든 개체가 Object.prototype에서 상속하는 hasOwnProperty 메서드를 사용해야합니다.
이를 설명하기 위해 아래에 특정 예가 제공됩니다.

	class A {
    
    
		name:string
		constructor(name:sting="defalut"){
    
    
			this.name = name
		}	
	}
	
	let a = new A()
	console.log(a.hasOwnProperty('name'));
	// true
	
	console.log(a.hasOwnProperty('abc'));
	// false
	
	console.log(a.hasOwnProperty('efg'));
	// false

참고 : 속성이 정의되지 않았는지 여부를 확인하는 것은 속성이 있는지 여부를 확인할 수 없습니다. 속성이 이미 존재할 수 있지만 값이 정의되지 않음으로 설정됩니다. hasOwnProperty 및 Object.keys ()는 속성을 처리하고 프로토 타입 체인을 통과하지 않는 JavaScript의 유일한 메서드입니다.


요약하자면

이 기사에서는 생성자 함수 프로토 타입의 프로토 타입, 생성 된 인스턴스 객체 (인스턴스)의 __proto__ 속성, 인스턴스의 __proto__ 속성을 가져 오는 Object.getPrototypeOf () 메서드를 소개합니다. 둘의 차이점과 사용법을 설명합니다. 인스턴스가 특정 속성 및 메서드를 찾으면 null이 될 때까지 __proto__ 속성 ​​체인에 따라 위쪽으로 쿼리하지만 전체 프로토 타입 체인을 순회하면 성능 문제가 발생합니다. hasOwnProperty () 및 Object.keys ()를 사용하여 속성이 있는지 확인합니다. 객체 인스턴스에서 이것은 전체 프로토 타입 체인을 통과하는 것을 방지합니다.

추천

출처blog.csdn.net/Suarez1987/article/details/112531456