> 웹 프론트엔드 > JS 튜토리얼 > 자바스크립트에서 객체를 생성하는 다양한 모드 분석(그래픽 튜토리얼)

자바스크립트에서 객체를 생성하는 다양한 모드 분석(그래픽 튜토리얼)

亚连
풀어 주다: 2018-05-21 14:15:04
원래의
1288명이 탐색했습니다.

이제 JavaScript로 객체를 생성하는 다양한 패턴을 분석해 보겠습니다. 이제 공유하고 참조하세요

JavaScript로 객체 생성

•팩토리 패턴

•생성자 패턴

•프로토타입 패턴

•생성자 패턴과 프로토타입 패턴 결합

•프로토타입 동적 패턴

대부분의 객체지향 언어는 클래스 개념을 가지고 있으며 이를 통해 동일한 메서드와 속성을 가진 여러 객체를 생성할 수 있습니다. 기술적으로 말하면 JavaScript는 객체 지향 언어이지만 JavaScript에는 클래스 개념이 없으며 모든 것이 객체입니다. 모든 객체는 기존 참조 유형을 통해 생성된 특정 참조 유형의 인스턴스입니다. 참조 유형은 기본 유형이거나 사용자 정의될 수 있습니다. 기본 참조 유형에는 개체, 배열, 데이터, RegExp 및 함수가 포함됩니다. ! 참조 유형은 종종 클래스라고 불리는 데이터와 기능을 구성하는 데이터 구조입니다. 클래스 개념이 부족한 자바스크립트에서는 객체를 어떻게 효율적으로 생성하느냐가 해결해야 할 문제이다.

1.1.0.객체 생성의 일반적인 방법

var person = {}; //对象字面量表示,等同于var person = new Objcect();
person.name = 'evansdiy';
person.age = '22';
person.friends = ['ajiao','tiantian','pangzi'];
person.logName = function() {
  console.log(this.name);
}
로그인 후 복사

객체 참조 유형을 기반으로 객체가 생성되며, 그 중 하나는 메서드입니다. 사람과 유사한 객체의 인스턴스가 많이 필요한 경우 중복된 코드가 많이 있을 것입니다.

1.1.1.팩토리 패턴

객체의 세부정보를 담을 수 있는 함수를 통해 객체를 생성한 후 객체를 반환합니다.

function person(name,age,friends) {

  var o = {
    name: name,
    age: age,
    friends: friends,
    logName: function() {
      console.log(this.name);
    }
  };

  return o;

}

var person1 = person('Evansdiy','22',['ajiao','tiantian','pangzi']);
로그인 후 복사

person 함수가 호출될 때마다 함수 내부의 객체 o를 통해 새로운 객체가 생성되고 반환됩니다. 이 외에 새로운 객체를 생성하기 위해 존재하는 이 내부 객체 o는 다른 목적이 없습니다. 또한, 팩토리 패턴으로 생성된 객체의 유형을 판별하는 것도 불가능합니다.

1.1.2.생성자 패턴

function Person(name,age,job) {

  this.name = name;
  this.age = age;
  this.job = job;
  this.logName = function() {
    console.log(this.name);
  }

}

//通过new操作符创建Person的实例
var person1 = new Person('boy-a','22','worker');

var person2 = new Person('girl-b','23','teacher');

person1.logName(); //boy-a

person2.logName(); //girl-a
로그인 후 복사

팩토리 패턴을 비교해 보면 여기서는 중간 객체를 생성할 필요도 없고 반환값도 없다는 것을 알 수 있습니다. 또한, 생성자의 인스턴스를 특정 타입으로 식별할 수 있어 객체 ​​식별 문제를 해결한다(인스턴스의 생성자 속성을 확인하거나, 인스턴스가 특정 생성자를 통해 생성되었는지 여부를 instanceof 연산자를 사용하여 확인). .

console.log(person1.constructor == Person);//constructor는 생성자 프로토타입에 위치하며 생성자를 가리키고 결과는 true입니다

console.log(person1 instanceof Person);//에 의해 판단됩니다. instanceof 연산자 person1이 생성자 Person의 인스턴스인지 여부에도 불구하고 생성자 패턴에도 고유한 문제가 있습니다. 실제로 logName 메서드는 인스턴스화에 의해 생성된 메서드가 동일하지 않다는 점에 유의해야 합니다. 코드는 false가 됩니다:

console.log(person1.logName == person2.logName); //false 이 문제를 해결하기 위해 메서드를 생성자 외부로 이동할 수 있습니다(전역 함수가 됨):

function logName() {
  console.log(this.name);
}

function logAge() {
  console.log(this.age);
}
로그인 후 복사

그러나 전역 컨텍스트에서 생성된 전역 함수는 실제로 Person이 생성한 인스턴스에서만 호출할 수 있습니다. 이는 이름에 걸맞지 않습니다. 메서드가 많으면 캡슐화가 부족하여 하나씩 정의해야 합니다.

1.1.3. 프로토타입 모드

JavaScript의 모든 함수에는 프로토타입 속성에 대한 포인터가 포함되어 있습니다(대부분의 브라우저는 내부 속성 __proto__를 통해 액세스할 수 있습니다). 프로토타입 속성은 모두가 공유하는 속성과 메서드를 포함하는 개체입니다. 참조 유형에 의해 생성된 인스턴스입니다.

function Person() {}

Person.name = 'evansdiy';

Person.prototype.friends = ['ajiao','jianjian','pangzi'];

Person.prototype.logName = function() {
  console.log(this.name);
}

var person1 = new Person();

person1.logName();//'evansdiy'
로그인 후 복사

위 코드는 다음 작업을 수행합니다.

1. Person 함수는 기본적으로 Person을 가리키는 생성자 속성만 포함하는 프로토타입 속성을 정의합니다. 세 가지 속성을 추가합니다. 그 중 하나는 메서드로 사용됩니다.

3 Person의 인스턴스를 만든 다음 해당 인스턴스에서 logName() 메서드를 호출합니다. !

여기서 주목해야 할 것은 logName() 메소드의 호출 프로세스입니다:

1. person1 인스턴스에서 logName() 메소드를 검색하여 해당 메소드가 없음을 확인하고 프로토타입을 다시 추적합니다. of person1

2. person1의 프로토타입에서 검색 logame() 메서드에는 이 메서드가 있으므로 이 메서드를 호출하는 것은 이러한 검색 프로세스를 기반으로 합니다. 인스턴스의 프로토타입에 있는 동일한 이름의 속성을 삭제하면 프로토타입에서 동일한 이름의 속성이 삭제되지 않고 인스턴스 액세스만 차단된다는 점에 유의해야 합니다.

var person2 = new Person();

person2.name = 'laocai'; 인스턴스에 더 이상 속성이 필요하지 않으면 삭제 연산자를 통해 삭제할 수 있습니다.

delete person2.name; for-in 루프를 사용하여 인스턴스에서 액세스할 수 있는 모든 속성을 열거합니다(속성이 인스턴스에 있거나 프로토타입에 있는지 여부).

for(i in person1) {
  console.log(i);
}
로그인 후 복사

동시에 다음을 사용할 수도 있습니다. hasOwnProperty() 메소드를 사용하여 속성이 인스턴스에 존재하는지 아니면 프로토타입에 존재하는지 확인합니다. 인스턴스에 속성이 존재하는 경우에만 true가 반환됩니다.

console.log(person1.hasOwnProperty('name'));//true!hasOwnProperty来自Object的原型,是javascript中唯一一个在处理属性时不查找原型链的方法。[via javascript秘密花园] 另外,也可以通过同时使用in操作符和hasOwnProperty()方法来判断某个属性存在于实例中还是存在于原型中:

console.log(('friends' in person1) && !person1.hasOwnProperty('friends'));先判断person1是否可以访问到friends属性,如果可以,再判断这个属性是否存在于实例当中(注意前面的!),如果不存在于实例中,就说明这个属性存在于原型中。 前面提到,原型也是对象,所以我们可以用对象字面量表示法书写原型,之前为原型添加代码的写法可以修改为:

Person.prototype = {

  name: 'evansdiy',
  friends: ['ajiao','jianjian','pangzi'],
  logName: function() {
    console.log(this.name);
  }

}
로그인 후 복사

由于对象字面量语法重写了整个prototype原型,原先创建构造函数时默认取得的constructor属性会指向Object构造函数:

//对象字面量重写原型之后
console.log(person1.constructor);//Object不过,instanceof操作符仍会返回希望的结果:

//对象字面量重写原型之后
console.log(person1 instanceof Person);//true当然,可以在原型中手动设置constructor的值来解决这个问题。

Person.prototype = {

  constructor: Person,
  ......

}
로그인 후 복사

如果在创建对象实例之后修改原型对象,那么对原型的修改会立即在所有对象实例中反映出来:

function Person() {};

var person1 = new Person();

Person.prototype.name = 'evansdiy';

console.log(person1.name);//'evansdiy'
로그인 후 복사

实例和原型之间的连接仅仅是一个指针,而不是一个原型的拷贝,在原型实际上是一次搜索过程,对原型对象的所做的任何修改都会在所有对象实例中反映出来,就算在创建实例之后修改原型,也是如此。 如果在创建对象实例之后重写原型对象,情况又会如何?

function Person() {};

var person1 = new Person1();//创建的实例引用的是最初的原型

//重写了原型
Person.prototype = {
  friends: ['ajiao','jianjian','pangzi']
}

var person2 = new Person();//这个实例引用新的原型

console.log(person2.friends);

console.log(person1.friends);
로그인 후 복사

以上代码在执行到最后一行时会出现未定义错误,如果我们用for-in循环枚举person1中的可访问属性时,会发现,里头空无一物,但是person2却可以访问到原型上的friends属性。 !重写原型切断了现有原型与之前创建的所有对象实例的联系,之前创建的对象实例的原型还在,只不过是旧的。

//创建person1时,原型对象还未被重写,因此,原型对象中的constructor还是默认的Person()
console.log(person1.constructor);//Person()

//但是person2的constructor指向Object()
console.log(person2.constructor);//Object()
로그인 후 복사

需要注意的是,原型模式忽略了为构造函数传递参数的过程,所有的实例都取得相同的属性值。同时,原型模式还存在着一个很大的问题,就是原型对象中的引用类型值会被所有实例共享,对引用类型值的修改,也会反映到所有对象实例当中。

function Person() {};

Person.prototype = {
  friends: ['ajiao','tiantian','pangzi']
}

var person1 = new Person();

var person2 = new Person();

person1.friends.push('laocai');

console.log(person2.friends);//['ajiao','tiantian','pangzi','laocai']
로그인 후 복사

修改person1的引用类型值friends,意味着person2中的friends也会发生变化,实际上,原型中保存的friends实际上只是一个指向堆中friends值的指针(这个指针的长度是固定的,保存在栈中),实例通过原型访问引用类型值时,也是按指针访问,而不是访问各自实例上的副本(这样的副本并不存在)。

1.1.4.结合构造函数和原型模式创建对象

结合构造函数和原型模式的优点,弥补各自的不足,利用构造函数传递初始化参数,在其中定义实例属性,利用原型定义公用方法和公共属性,该模式应用最为广泛。

function Person(name,age) {

  this.name = name;
  this.age = age;
  this.friends = ['ajiao','jianjian','pangzi'];

}

Person.prototype = {

  constructor: Person,
  logName: function() {
    console.log(this.name);
  }

}

var person1 = new Person('evansdiy','22');

var person2 = new Person('amy','21');

person1.logName();//'evansdiy'

person1.friends.push('haixao');

console.log(person2.friends.length);//3
로그인 후 복사

1.1.5.原型动态模式

原型动态模式将需要的所有信息都封装到构造函数中,通过if语句判断原型中的某个属性是否存在,若不存在(在第一次调用这个构造函数的时候),执行if语句内部的原型初始化代码。

function Person(name,age) {

  this.name = name;
  this.age = age;

  if(typeof this.logName != 'function') {
    Person.prototype.logName = function() {
      console.log(this.name);
    };
    Person.prototype.logAge = function() {
      console.log(this.age);
    };
  };

}

var person1 = new Person('evansdiy','22');//初次调用构造函数,此时修改了原型

var person2 = new Person('amy','21');//此时logName()方法已经存在,不会再修改原型
로그인 후 복사

需要注意的是,该模式不能使用对象字面量语法书写原型对象(这样会重写原型对象)。若重写原型,那么通过构造函数创建的第一实例可以访问的原型对象不会包含if语句中的原型对象属性。

function Person(name,age) {

  this.name = name;
  this.age = age;

  if(typeof this.logName != 'function') {
    Person.prototype = {
      logName: function() {
        console.log(this.name);
      },
      logAge: function() {
        console.log(this.Age);
      }
    }
  };

}

var person1 = new Person('evansdiy','22');

var person2 = new Person('amy','21');

person2.logName();//'amy'

person1.logName();//logName()方法不存在
로그인 후 복사

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

详细解读JavaScript设计模式开发中的桥接模式(高级篇)

详细解读在JavaScript中实现设计模式中的适配器模式的方法(图文教程)

设计模式中的facade外观模式在JavaScript开发中的运用(高级篇)

위 내용은 자바스크립트에서 객체를 생성하는 다양한 모드 분석(그래픽 튜토리얼)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿