javascript – So kombinieren Sie Konstruktormuster und Prototypmuster in js
曾经蜡笔没有小新
曾经蜡笔没有小新 2017-05-19 10:33:10
0
5
634

Die Schreibmethode in der fortgeschrittenen Programmierung ist wie folgt

function Person(name,age,job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.lessons = ['Math','Physics'];
}
Person.prototype = {
    constructor: Person,
    getName: function(){
        return this.name;
    }
}

Wenn ich es also so schreibe, ist es dann dasselbe? Der einzige Unterschied besteht darin, dass ihre Konstrukte unterschiedlich sind?

function Person(name,age,job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.lessons = ['Math','Physics'];
    Person.prototype.getName = function(){
        return this.name;
    }
}
曾经蜡笔没有小新
曾经蜡笔没有小新

Antworte allen(5)
洪涛

prototype定义(的位置)写在构造函数内或外的区别 ?

第二种写法每次创建实例都会执行一遍对prototype的操作! 关键是这个操作很没意义,这个方法对每个实例都是相同的。
第一种方法中, 当prototype在构造函数外面书写时,可以从形式上和内存分配中解决重复定义或分配内存的问题。
对应在内存中,第一种写法,无论你创建了多少实例,每个实例占据空间只是name, age,job和lessons。getName在内存中只有一份,所有实例共用; 第二种写法,每个新创建的实例会分配一块额外的空间(栈)来执行prototype的定义。

prototype在第一种方法中赋值的方式和第二种方法有何区别?

区别很大的,一个function类定义好,它默认的 constructor属性就是自己, 它的实例在访问constructor属性时会返回这个值。

function Person() {};
console.log(Person.prototype.constructor);  // Person

var p = new Person();
console.log(p.constructor);   // Person    表示p的构造函数是Person类

方法1中为什么要定义constructor? 因为它给prototype重新赋值了,如果你不定义constructor(Person.prototype = {getName: function() {}}),那么上例中p.constructor返回值将是 Object, 即p的构造函数是Object,显然与事实不符。

方法1更明智的做法是不要重新给prototype赋值,只为prototype添加我们需要的属性getName, 改为 Person.prototype.getName = function() {return this.name;},也就是第二种方法里的定义方法,这么写就不会覆盖prototype的默认属性。

習慣沉默
首先,你应该搞清楚js中的原型,在js中,原型指的是构造函数的prototype属性的值,由构造函数创建出来的实例会自动链接到原型对象也就是其构造函数的prototype属性上。
    function Person(name,age,job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.lessons = ['Math','Physics'];
}
Person.prototype = {
    constructor: Person,
    getName: function(){
        return this.name;
    }
}
这个写法中,Person为构造函数,可以创建出一个实例对象,
var p=new Person();
然后p可以继承原型中的属性,在原型中constructor指向的是当前的构造函数
你的写法可以理解为在构造函数中给原型的getname属性赋值了一个函数
PHPzhong

前一种写法重写了prototype,而你的写法只是在prototype里增加了一个方法而已,两个是不同的方式

世界只因有你

按照你的写法会在每一次实例化过程中重新再分配存储空间给实例,而原型模式的意义之一在于所有实例都可以共享原型上的属性和方法,虽然单独这么做有缺陷。第二点就是我还是倾向于给原型对象对象字面量的写法,个人认为一个是比较直观,第二是有利于维护。如下:

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

一定要写constructor属性,不然会发生指向的错误,此时是重写了原型对象,如果不指明这个属性就无法起到原型链应有的作用。

为情所困

原型继承和构造函数有很多的不同,原型继承即原型链继承。

原型链并非十分完美, 它包含如下两个问题.

问题一: 当原型链中包含引用类型值的原型时,该引用类型值会被所有实例共享;

问题二: 在创建子类型(例如创建Son的实例)时,不能向超类型(例如Father)的构造函数中传递参数.

有鉴于此, 实践中很少会单独使用原型链.

为此,下面将有一些尝试以弥补原型链的不足.

借用构造函数

为解决原型链中上述两个问题, 我们开始使用一种叫做借用构造函数(constructor stealing)的技术(也叫经典继承).

基本思想:即在子类型构造函数的内部调用超类型构造函数.

function Father(){
    this.colors = ["red","blue","green"];
}
function Son(){
    Father.call(this);//继承了Father,且向父类型传递参数
}
var instance1 = new Son();
instance1.colors.push("black");
console.log(instance1.colors);//"red,blue,green,black"

var instance2 = new Son();
console.log(instance2.colors);//"red,blue,green" 可见引用类型值是独立的

很明显,借用构造函数一举解决了原型链的两大问题:

其一, 保证了原型链中引用类型值的独立,不再被所有实例共享;

其二, 子类型创建时也能够向父类型传递参数.

随之而来的是, 如果仅仅借用构造函数,那么将无法避免构造函数模式存在的问题--方法都在构造函数中定义, 因此函数复用也就不可用了.而且超类型(如Father)中定义的方法,对子类型而言也是不可见的. 考虑此,借用构造函数的技术也很少单独使用.
更多请参考 JS原型链与继承别再被问倒了,喜欢就点赞支持一下,谢谢!

Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage