>  기사  >  웹 프론트엔드  >  Javascript 프로토타입 chain_javascript 기술의 원리에 대한 자세한 설명

Javascript 프로토타입 chain_javascript 기술의 원리에 대한 자세한 설명

WBOY
WBOY원래의
2016-05-16 15:21:421459검색

이 기사에서는 예제를 통해 Javascript 프로토타입 체인의 원리를 분석합니다. 참고하실 수 있도록 모든 사람과 공유하세요. 자세한 내용은 다음과 같습니다.

1. 자바스크립트 프로토타입 체인

ECMAScript는 프로토타입 체인의 개념을 설명하고 프로토타입 체인을 주요 방법으로 사용하여 상속을 구현합니다. 기본 아이디어는 프로토타입을 사용하여 하나의 참조 유형이 다른 참조 유형의 속성과 메서드를 상속하도록 하는 것입니다. JavaScript에서 __proto__ 속성은 객체의 프로토타입 체인을 나타내는 데 사용됩니다. 객체의 속성을 찾을 때 JavaScript는 주어진 이름을 가진 속성을 찾을 때까지 프로토타입 체인을 탐색합니다!

예를 들어, 이제 다음과 같은 코드가 있습니다.

Object 클래스 확장 및 Clone 및 Extend 메소드 추가

/*扩展Object类,添加Clone,JS实现克隆的方法*/
Object.prototype.Clone = function(){
  var objClone;
  if (this.constructor == Object){
    objClone = new this.constructor(); 
  }else{
    objClone = new this.constructor(this.valueOf()); 
  }
  for(var key in this){
    if ( objClone[key] != this[key] ){ 
      if ( typeof(this[key]) == 'object' ){ 
        objClone[key] = this[key].Clone();
      }else{
        objClone[key] = this[key];
      }
    }
  }
  objClone.toString = this.toString;
  objClone.valueOf = this.valueOf;
  return objClone; 
}
/*扩展Object类,添加Extend方法来实现JS继承, 目标对象将拥有源对象的所有属性和方法*/
Object.prototype.Extend = function (objDestination, objSource) {
  for (var key in objSource) {
    if (objSource.hasOwnProperty(key) && objDestination[key] === undefined) {
      objDestination[key] = objSource[key];
    }
  }
  return objDestination;
}

Person 클래스 정의

/*定义一个Person类*/
 function Person(_name,_age){
   this.name = _name;
   this.age = _age;
}

JavaScript에서 Object 클래스는 모든 클래스의 상위 클래스이므로 Person 클래스는 Object 클래스를 상속하고 새로 추가된 Clone 및 Extend를 포함하여 Object 클래스의 모든 공용 속성과 공용 메서드를 상속합니다. Object 클래스의 메서드

다음 코드를 사용하여 Person 클래스가 실제로 Object 클래스를 상속한다는 것을 증명할 수 있습니다

document.write("<pre class="brush:php;toolbar:false">");
var p = new Person("孤傲苍狼",24);//创建一个人,名字是孤傲苍狼
var cloneP = p.Clone();//p调用在Object类中定义的Clone方法来克隆自己,如果能得到一个cloneP,那就证明了Person类确实是继承了Object类,所以就拥有了Clone
document.writeln("p是使用Person类以构造函数的方式创建出来的对象,p.name = "+p.name+",p.age = "+p.age);
document.writeln("cloneP是p调用Clone方法克隆出来的对象,cloneP.name = "+cloneP.name+",cloneP.age = "+cloneP.age);
document.writeln("cloneP对象和p对象是两个相互独立的对象,这两个对象的内存地址肯定是不相等,p == cloneP的结果是:"+(p == cloneP));
cloneP.name="白虎神皇";//修改cloneP的名字
document.writeln("cloneP的name被修改了,cloneP.name = "+cloneP.name);
document.writeln("cloneP的name修改了,但是不影响到p,p.name = "+p.name);
document.write("
");

실행 결과:

그런 다음 Person 클래스는 Shenma 메서드를 통해 Object 클래스를 상속합니다. 프로토타입(prototye) 메서드를 사용하여 상속됩니다.

/*定义一个Person类*/
function Person(_name,_age){
   this.name = _name;
   this.age = _age;
}
Person.prototype = new Object();//让Person类继承Object类

JavaScript에서는 모든 클래스가 Object 클래스에서 상속된다고 규정하므로 "Person.prototype = new Object();//Person 클래스가 Object 클래스를 상속받도록 "라고 쓰지 않더라도 JavaScript 엔진이 자동으로 이 문장을 추가하거나 "Person.prototype = Object.prototype;"을 사용하여 Person 클래스가 Object 클래스를 상속하도록 할 것입니다. "Person.prototype = new Object();", 실제로 이는 Object 객체가 Person의 프로토타입이 되는 것과 동일합니다. 이는 Object 객체의 속성과 메서드를 Person에 복사하는 것과 같습니다. .

2. 새로운 운영자의 업무 방식

먼저 이 코드를 살펴보겠습니다.

코드 복사 코드는 다음과 같습니다.
var p = new Person("lonewolf",24);// Lone Ao Canglang이라는 사람 만들기

아주 간단한 코드로, 이 새로운 기능이 무엇인지 살펴보겠습니다. 새로운 프로세스는 다음 세 단계로 나눌 수 있습니다.

1.var p={}; 객체 p를 초기화합니다.

2. p.__proto__=Person.prototype;, 객체 p의 __proto__ 속성을 Person.prototype으로 설정합니다

3.Person.call(p,"lonewolf",24) 생성자 Person을 호출하여 p를 초기화합니다.

핵심은 두 번째 단계에 있습니다. 이를 증명해 보겠습니다.

var p = new Person("孤傲苍狼",24);//创建一个人,名字是孤傲苍狼
alert("p.__proto__ === Person.prototype的结果是:"+(p.__proto__ === Person.prototype));

Firefox에서 실행한 결과는 다음과 같습니다.

이 코드는 true를 반환합니다. 2단계가 정확하다고 설명하세요.

참고: __proto__ 속성은 Firefox 또는 Chrome 브라우저에서만 공개적으로 액세스할 수 있습니다. 따라서 IE 커널을 기반으로 하는 다른 브라우저에서는 true를 반환하지 않습니다.

그럼 __proto__는 무엇인가요? 여기서 간단히 얘기해보자. 각 개체는 그 안에 있는 속성, 즉 __proto__를 초기화합니다. 개체의 속성에 액세스할 때 이 속성이 개체 내에 존재하지 않으면 개체는 __proto__로 이동하여 속성을 찾습니다. 이 __proto__는 자체적인 속성을 갖습니다. __proto__, 그래서 계속 찾아보게 되는데, 우리가 흔히 프로토타입 체인이라고 부르는 개념이죠.

표준에 따르면 __proto__는 공개 속성이 아닙니다. 즉, __proto__ 속성은 IE에서 액세스할 수 없지만 Firefox 엔진은 이를 공개하여 액세스할 수 있게 만듭니다. 외부에서 설정합니다.

좋습니다. 개념은 명확합니다. 다음 코드를 살펴보겠습니다.

<script type="text/javascript">
    var Person = function () { };
    Person.prototype.Say = function () {
      alert("Person say");
    }
    var p = new Person();
    p.Say();
</script>

이 코드는 왜 p가 Person's Say에 접근할 수 있는지 살펴보겠습니다.

우선

코드 복사 코드는 다음과 같습니다.
var p=new Person();

결론은

코드 복사 코드는 다음과 같습니다.
p.__proto__=Person.prototype

그래서 p.Say()를 호출할 때 우선 p에는 Say 속성이 없으므로 Person.prototype인 __proto__에서 이를 찾아야 하며 위에서 정의했습니다.

Person.prototype.Say=function(){
    alert("Person say");
};

于是,就找到了这个方法。

接下来,让我们看个更复杂的。

<script type="text/javascript">
    var Person = function () { };
    Person.prototype.Say = function () {
      alert("Person say");
    }
    Person.prototype.Salary = 50000;
    var Programmer = function () { };
    Programmer.prototype = new Person();//让程序员类从人这个类继承
    Programmer.prototype.WriteCode = function () {
      alert("programmer writes code");
    };
    Programmer.prototype.Salary = 500;
    var p = new Programmer();
    p.Say();
    p.WriteCode();
    alert(p.Salary);
</script>

我们来做这样的推导:

复制代码 代码如下:
var p=new Programmer();

可以得出

复制代码 代码如下:
p.__proto__=Programmer.prototype;

而在上面我们指定了

复制代码 代码如下:
Programmer.prototype=new Person();

我们来这样拆分,

var p1=new Person();
Programmer.prototype=p1;

那么:

p1.__proto__=Person.prototype;
Programmer.prototype.__proto__=Person.prototype;

由根据上面得到

复制代码 代码如下:
p.__proto__=Programmer.prototype

可以得到:

复制代码 代码如下:
p.__proto__.__proto__=Person.prototype

好,算清楚了之后我们来看上面的结果,p.Say()。由于p没有Say这个属性,于是去 p.__proto__,也就是Programmer.prototype,也就是p1中去找,由于p1中也没有Say,那就去 p.__proto__.__proto__,也就是Person.prototype中去找,于是就找到了Say方法。这也就是原型链的实现原理。

以下代码展示了JS引擎如何查找属性:

function getProperty(obj, prop) {
  if (obj.hasOwnProperty(prop))
    return obj[prop];
  else if (obj.__proto__ !== null)
    return getProperty(obj.__proto__, prop);//递归
  else
    return undefined;
}

范例:查找p对象的Say方法

<script type="text/javascript">
  /*查找obj对象的prop属性*/
   function getProperty(obj, prop) {
    if (obj.hasOwnProperty(prop))
      return obj[prop];
    else if (obj.__proto__ !== null)
      return getProperty(obj.__proto__, prop);//递归
    else
      return undefined;
  }
  var Person = function () { };//定义Person类
  Person.prototype.Say = function () {
    alert("Person say");
  }
  Person.prototype.Salary = 50000;
  var Programmer = function () { };//定义Programmer类
  //Programmer.prototype = new Person();//让程序员类从人这个类继承,写法一
  Programmer.prototype = Person.prototype;//让程序员类从人这个类继承,写法二
  Programmer.prototype.WriteCode = function () {
    alert("programmer writes code");
  };
  Programmer.prototype.Salary = 500;
  var p = new Programmer();
  var SayFn = getProperty(p,"Say");//查找p对象的Say方法
  SayFn.call(p);//调用找到的Say方法
</script>

在火狐下的运行结果:

其实prototype只是一个假象,他在实现原型链中只是起到了一个辅助作用,换句话说,他只是在new的时候有着一定的价值,而原型链的本质,其实在于__proto__。

希望本文所述对大家JavaScript程序设计有所帮助。

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