이 기사는 생성자, 프로토타입 및 클래스 구문 설탕과 관련된 문제를 포함하여 javascript의 상속 및 프로토타입 체인에 대한 지식을 제공합니다.
자바스크립트의 상속과 프로토타입 체인은 제가 프론트엔드를 배우는 과정에서 접한 드물고 이해하기 어려운 부분입니다. . 여기에는 제가 알고 배운 내용을 모두 기록해 두었습니다. 여전히 어려움을 겪고 있는 형제들에게 작은 도움이 되기를 바랍니다. 여러분의 비판과 정정도 환영합니다.
생성자는 인스턴스 멤버와 정적 멤버로 구성됩니다. 여기서 인스턴스 멤버는 함수 내부의 this 키워드를 통해 추가된 멤버입니다. 개체를 인스턴스화한 후 인스턴스화된 개체를 통해 액세스할 수 있는 반면 정적 멤버는 함수 자체에 추가된 멤버이며 생성자를 통해서만 액세스할 수 있습니다.
//创造一个构造函数let Father = function(name,age){ //实例成员 this.name = name; this.age = age; this.method = "我是一个实例成员";} //静态成员Father.like = "mother"; //检验实例对象是否能够被构造函数直接访问console.log(Father.method); //undefinedconsole.log(Father.like); //mother //实例化一个对象let father = new Father("小王",27); //检验静态对象是否能够被实例化对象访问console.log(father.name); //小王console.log(father.age); //27console.log(father.like); //undefined
new 키워드를 사용하면 생성자를 통해 인스턴스화된 객체를 구현할 수 있는데, 특정 인스턴스화 과정에서는 어떤 일이 발생할까요? 이는 대략 다음 단계로 나눌 수 있습니다.
(1) 빈 객체 son 만들기 {}
(2) son son.__proto__ = Father.prototype
son.__proto__ = Father.prototype
(3) 重新绑定this,使构造函数的this指向新对象 Father.call(this)
(4) 为新对象属性赋值 son.name
(5) 返回this return this
,此时的新对象就拥有了构造函数的方法和属性了
构造函数的方法分为两种,第一种为在函数内部直接定义的方法,第二种为通过原型添加的方法;
//函数内部直接定义的方法let Father = function(){ this.read = function(){ console.log("我是内部定义的read方法!"); }}//通过JavaScript 상속 및 프로토타입 체인에 대한 간략한 분석添加的方法Father.prototype.look = function(){ console.log("我是通过JavaScript 상속 및 프로토타입 체인에 대한 간략한 분석定义的look方法!");} //实例化对象进行检验let father1 = new Father();let father2 = new Father(); father1.read(); //我是内部定义的read方法!father2.read(); //我是内部定义的read方法!console.log(father1.read === father2.read); //falsefather1.look(); //我是通过JavaScript 상속 및 프로토타입 체인에 대한 간략한 분석定义的look方法!father2.look(); //我是通过JavaScript 상속 및 프로토타입 체인에 대한 간략한 분석定义的look方法!console.log(father1.look === father2.look); /true
可以发现,函数内部直接定义的方法在每实例化一个新的对象以后,都会给这个方法分配一个新的内存空间,而通过原型添加的方法便会共享一个空间。
不存在内存空间的问题,判断时看其值是否相同;
let Father = function(name){ this.name = name;}let father1 = new Father("小王"); let father2 = new Father("小红"); console.log(father1.name === father2.name); //falselet father1 = new Father("小王"); let father2 = new Father("小王"); console.log(father1.name === father2.name); //true
因此我们可以总结一下定义构造函数的基本规则,即公共属性定义到构造函数里面,公共方法我们放到原型对象身上。
Father.prototype 就是原型,它是一个对象,也可以称为原型对象。
原型的作用,就是共享方法。
我们通过 Father.prototype.method
可以共享方法,不会反应开辟空间存储方法。
原型中this的指向是实例。
JavaScript 상속 및 프로토타입 체인에 대한 간략한 분석本人感觉是一个对于初学者或者说是部分前端菜鸡(例如本人)来说特别难以理解的东西,为了让下面的部分更容易理解,这里强行先记住以下几点:
__proto__
是每个对象都有的属性,prototype是每个函数特有的方法;__proto__
属性都会指向自身构造函数的prototype;Function.__proto__
=== Function.prototype;Object.prototype.__proto__
=== null 也就是JavaScript 상속 및 프로토타입 체인에 대한 간략한 분석的终点;原型与原型层层相链接的过程即为JavaScript 상속 및 프로토타입 체인에 대한 간략한 분석。
对象可以使用构造函数prototype原型对象的属性和方法,就是因为对象有__proto__
原型的存在每个对象都有__proto__
Father.call(this)
를 가리키도록 이것을 다시 바인딩합니다.(4) 새 개체 속성 son.name에 값을 할당합니다.
( 5) Return this return this
이때 새 객체는 생성자의 메서드와 속성을 갖게 됩니다.
함수를 구성하는 방법에는 두 가지가 있습니다. 첫 번째는 함수 내부에서 직접 정의한 메소드이고, 두 번째는 프로토타입을 통해 추가한 메소드입니다. 새 객체를 인스턴스화한 후 이 메서드에 새 메모리 공간이 할당되고 프로토타입을 통해 추가된 메서드는 동일한 공간을 공유합니다.
let Father = function(name){ this.name = name;}let father = new Father("老王");console.log(father.__proto__ === Father.prototype); //true //验证上述说法中的第二条
그래서 생성자 정의에 대한 기본 규칙, 즉
공용 속성이 정의됩니다. 생성자에 있고 공용 메소드는 프로토타입 객체에 배치됩니다. 3. 프로토타입 🎜3.1 프로토타입이란 무엇입니까? 🎜🎜Father.prototype은 프로토타입 객체이며 프로토타입 객체라고도 합니다. 🎜🎜3.2 프로토타입의 역할은 무엇인가요?🎜🎜프로토타입의 역할은 방법을 공유하는 것입니다. 🎜🎜공간 저장 방식을 반영하지 않는Father.prototype.method
를 통해 메소드를 공유할 수 있습니다. 🎜🎜3.3 프로토타입의 이 항목은 어디를 가리킵니까? 🎜🎜프로토타입의 이 항목은 인스턴스를 가리킵니다. 🎜🎜🎜4. 프로토타입 체인 🎜🎜🎜 프로토타입 체인은 초보자나 일부 프런트엔드 초보자(나 같은)에게 특히 이해하기 어려운 부분이라고 생각합니다. 강제로 적용됩니다. 다음 사항을 기억하세요. 🎜__proto__
는 각 객체의 속성이고, 프로토타입은 각 함수에 고유한 메서드입니다. __proto__
속성은 자체 생성자의 프로토타입을 가리킵니다. Object.prototype.__proto__
=== null은 프로토타입 체인의 끝입니다.__proto__
를 갖고 각 객체는 __proto__
를 가지므로 생성자 프로토타입 프로토타입 객체의 속성과 메소드를 사용할 수 있습니다. 프로토타입의 존재 🎜function Star(name) { this.name = name; //(1)首先看obj对象身上是否有dance方法,如果有,则执行对象身上的方法 this.dance = function () { console.log(this.name + '1'); }}//(2)如果没有dance方法,就去构造函数原型对象prototype身上去查找dance这个方法。Star.prototype.dance = function () { console.log(this.name + '2');}; //(3)如果再没有dance方法,就去Object原型对象prototype身上去查找dance这个方法。Object.prototype.dance = function () { console.log(this.name + '3');}; //(4)如果再没有,则会报错。let obj = new Star('小红');obj.dance();🎜4.3 프로토타입 체인 다이어그램🎜🎜🎜🎜🎜처음 몇 가지 사항을 종합해 보면 위 그림을 이해하는 데 큰 문제가 없을 것입니다. 그림에서 동그라미 친 부분은 끔찍한 프로토타입 체인입니다. 🎜🎜4.4 프로토타입 체인 검색 방법🎜
function Star(name) { this.name = name;}Star.prototype = { dance:function(){ console.log("重定义prototype"); }}Star.prototype.constructor = Star;🎜(1) 먼저 obj 객체에 댄스 메소드가 있는지 확인하세요. 그렇다면 해당 객체에 메소드를 실행하세요. 🎜🎜(2) 댄스 메소드가 없으면 생성자 프로토타입 객체 프로토타입으로 이동하여 댄스 메소드를 찾습니다. 🎜🎜(3) 댄스 방법이 없으면 객체 프로토타입 개체 프로토타입으로 이동하여 댄스 방법을 찾습니다. 🎜🎜(4) 더 이상 없으면 오류가 보고됩니다. 🎜
有两种添加方法,第一种为上面的写法,直接通过 构造函数.prototype.方法名 进行添加;第二种为重定义构造函数的prototype,但是此种情况会丢失掉原有的constructor构造器,所以一定要再连接回去,例子如下:
function Star(name) { this.name = name;}Star.prototype = { dance:function(){ console.log("重定义prototype"); }}Star.prototype.constructor = Star;
另外,类似于Array、String这些内置的类是不能这么处理的。
这里就长话短说,首先我们要明确继承需要继承哪些东西,在前文中我们提到了定义构造函数的基本规则,即**公共属性定义到构造函数里面,公共方法我们放到原型对象身上。**我们所需要继承的东西也不外乎就这二者,公共属性的继承可以通过call()或者apply()进行this的指向定义,而公共方法可以通过原型对象的赋值进行处理,因此我们很容易想到如下的方法:
//定义一个父类function Father(name) { this.name = name;}Father.prototype.dance = function () { console.log('I am dancing');};//定义一个子类function Son(name, age) { Father.call(this, name); this.age = age;}//通过赋值的方法连接Son.prototype = Father.prototype;//为子类添加方法Son.prototype.sing = function () { console.log('I am singing');}; let son = new Son('小红', 100); //此时父类也被影响了console.log(Father.prototype) //{dance: ƒ, sing: ƒ, constructor: ƒ}
很显然,当我们只想修改子类里面的方法时,显然上述方法不太合适;因此 我们可以尝试new一个新的父类出来,代码如下:
function Father(name) { this.name = name;}Father.prototype.dance = function () { console.log('I am dancing');};function Son(name, age) { Father.call(this, name); this.age = age;}Son.prototype = new Father();Son.prototype.sing = function () { console.log('I am singing');};let son = new Son('小红', 100);console.log(Father.prototype) //{dance: ƒ, constructor: ƒ}
对于以前了解过面向对象编程的程序员来讲,上述关于继承的写法属实让人有些难以接受,因此在es6里面新增了一个语法糖来更方便更便捷地书写继承,这里就直接上代码了;
class Father { constructor(name) { this.name = name; } dance() { console.log("我是" + this.name + ",我今年" + this.age + "岁," + "我在跳舞"); }}class Son extends Father { constructor(name, age) { super(name); this.age = age; } sing() { console.log("我是" + this.name + ",我今年" + this.age + "岁," + "我在唱歌"); }}let obj = new Son('小红', 19); obj.sing();obj.dance();
分析一下上面代码,首先一个类(构造函数)里面依旧为两部分,即公共属性和公共方法,constructor() 里面存放了该构造函数的公共属性,后面接着的便是公共方法,extends 关键字表示继承的是哪个类,super() 便是将里面父类里面相应的公共属性拿出来,这样看下来便可以将代码规整许多。
相关推荐:javascript学习教程
위 내용은 JavaScript 상속 및 프로토타입 체인에 대한 간략한 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!