เทคนิคใดที่สามารถใช้เพื่อกำหนดคลาสใน JavaScript และการแลกเปลี่ยนของพวกเขาคืออะไร


686

ฉันชอบที่จะใช้ OOP ในโครงการขนาดใหญ่อย่างที่ฉันกำลังทำอยู่ตอนนี้ ฉันต้องสร้างหลายคลาสใน JavaScript แต่ถ้าฉันไม่เข้าใจผิดมีอย่างน้อยสองวิธีที่จะทำเช่นนั้น ไวยากรณ์จะเป็นอย่างไรและทำไมจึงต้องทำเช่นนั้น?

ฉันต้องการหลีกเลี่ยงการใช้ห้องสมุดบุคคลที่สามอย่างน้อยตอนแรก
ค้นหาคำตอบอื่น ๆ ฉันพบบทความการเขียนโปรแกรมเชิงวัตถุด้วย JavaScript ตอนที่ 1: การสืบทอด - Doc JavaScriptที่กล่าวถึงการเขียนโปรแกรมเชิงวัตถุใน JavaScript มีวิธีที่ดีกว่าในการรับมรดกหรือไม่


หมายเหตุ: นี่เป็นไฟล์ซ้ำซ้อนของstackoverflow.com/questions/355848
Jason S

3
โดยส่วนตัวฉันชอบประกาศสมาชิกชั้นเรียนในส่วนของฟังก์ชั่น ฉันใช้เทคนิค 'ตรึงสิ่งนี้' เพื่อสร้างการปิดเพื่อให้มันทำงานเหมือนคลาสมากขึ้น ฉันมีตัวอย่างรายละเอียดในบล็อกของฉัน: ncombo.wordpress.com/2012/12/30/…
Jon

ฉันได้พอร์ตส่วนใหญ่ของฟังก์ชั่น C ++ OOP ไปยัง JavaScript ด้วยไวยากรณ์ที่เรียบง่ายและเป็นธรรมชาติ ดูคำตอบของฉันที่นี่: stackoverflow.com/a/18239463/1115652

ไม่มีคลาสใน JavaScript แต่ถ้าคุณต้องการจำลองพฤติกรรมที่เหมือนกันในคลาสใน JS คุณสามารถทำได้ ดูรายละเอียดใน: symfony-world.blogspot.com/2013/10/…
ducin

คำตอบ:


743

นี่คือวิธีในการทำโดยไม่ต้องใช้ไลบรารีภายนอก:

// Define a class like this
function Person(name, gender){

   // Add object properties like this
   this.name = name;
   this.gender = gender;
}

// Add methods like this.  All Person objects will be able to invoke this
Person.prototype.speak = function(){
    alert("Howdy, my name is" + this.name);
};

// Instantiate new objects with 'new'
var person = new Person("Bob", "M");

// Invoke methods like this
person.speak(); // alerts "Howdy, my name is Bob"

ตอนนี้คำตอบที่แท้จริงนั้นซับซ้อนกว่านั้นทั้งหมด ตัวอย่างเช่นไม่มีสิ่งเช่นคลาสใน JavaScript JavaScript ใช้prototypeโครงร่างการสืบทอด

นอกจากนี้ยังมีห้องสมุด JavaScript ยอดนิยมจำนวนมากที่มีสไตล์ของตัวเองในการประมาณฟังก์ชั่นคล้ายชั้นเรียนใน JavaScript คุณจะต้องการที่จะตรวจสอบอย่างน้อยต้นแบบและjQuery

การตัดสินใจว่าสิ่งใดเป็น "ดีที่สุด" ซึ่งเป็นวิธีที่ดีในการเริ่มสงครามศักดิ์สิทธิ์ใน Stack Overflow หากคุณกำลังเริ่มโครงการ JavaScript ที่มีขนาดใหญ่ขึ้นมันคุ้มค่าที่จะเรียนรู้ห้องสมุดยอดนิยมและทำสิ่งที่พวกเขาต้องการ ฉันเป็นคนต้นแบบ แต่ Stack Overflow ดูเหมือนจะเอนไปทาง jQuery

เท่าที่มีเพียง "ทางเดียวที่จะทำ" โดยไม่มีการอ้างอิงใด ๆ ในห้องสมุดภายนอกวิธีที่ฉันเขียนมันค่อนข้างสวย


48
แต่มันไม่ทำงานเหมือนภาษา X ที่ฉันได้เรียนรู้วิธีการที่จริงที่สิ่งที่ใช้ในการสร้างอินสแตนซ์ของวัตถุควรใช้งานได้ :(
Erik Reppen

2
ตามdeveloper.mozilla.org/en-US/docs/Web/JavaScript/...คุณสมบัติยังควรจะเพิ่มต้นแบบ ( "Person.prototype.name = '';")
DaveD

1
@DaveD - อาจเป็นไปได้ แต่ดูเหมือนจะไม่อีกต่อไป .. ?
Kieren Johnstone

6
jQuery ไม่ได้ให้วิธีการสร้างฟังก์ชั่นที่เหมือนคลาสได้เลย ??? (ทุกคลาสมี CSS คลาส) คุณควรลบออกจากส่วนนั้นของคำตอบ
Bergi

7
จากครึ่งปีที่สองของปี 2015 EcmaScript 6 มาตรฐานใหม่เปิดตัวดังนั้นฉันขอเสนอให้ทำวิธีใหม่ (ทำความสะอาดและประหยัดยิ่งขึ้น
DevWL

213

วิธีที่ดีที่สุดในการกำหนดคลาสใน JavaScript คือการไม่กำหนดคลาส

อย่างจริงจัง.

การวางแนวของวัตถุมีหลายรสชาติบางอย่าง ได้แก่ :

  • คลาส OO (เปิดตัวครั้งแรกโดย Smalltalk)
  • ต้นแบบตาม OO (แนะนำตัวครั้งแรกโดยตนเอง)
  • OO แบบหลายวิธี (คิดเป็นครั้งแรกโดย CommonLoops ฉันคิดว่า)
  • คำกริยา OO (ไม่มีความคิด)

และบางทีคนอื่น ๆ ที่ฉันไม่รู้

JavaScript ใช้ OO ที่ใช้ต้นแบบ ใน OO ที่ใช้ต้นแบบวัตถุใหม่จะถูกสร้างขึ้นโดยการคัดลอกวัตถุอื่น (แทนที่จะเป็นอินสแตนซ์จากคลาสเทมเพลต) และวิธีการอาศัยอยู่ในวัตถุโดยตรงแทนที่จะเป็นในชั้นเรียน การสืบทอดจะกระทำผ่านการมอบหมาย: ถ้าวัตถุไม่มีวิธีหรือคุณสมบัติมันจะค้นหาบนต้นแบบ (s) (เช่นวัตถุที่ถูกโคลนจาก) จากนั้นเป็นต้นแบบของต้นแบบเป็นต้น

ในคำอื่น ๆ : ไม่มีชั้นเรียน

JavaScript มีการปรับแต่งที่ดีของตัวแบบนั้น: constructors ไม่เพียง แต่คุณสามารถสร้างวัตถุโดยการคัดลอกวัตถุที่มีอยู่คุณยังสามารถสร้างวัตถุเหล่านั้นได้ "ออกมาจากอากาศ" เพื่อพูด หากคุณเรียกใช้ฟังก์ชันที่มีnewคำหลักฟังก์ชันนั้นจะกลายเป็นตัวสร้างและthisคำหลักจะไม่ชี้ไปที่วัตถุปัจจุบัน แต่จะเรียกว่า "ว่าง" ที่สร้างขึ้นใหม่แทน ดังนั้นคุณสามารถกำหนดค่าวัตถุในแบบที่คุณชอบ ด้วยวิธีดังกล่าวผู้สร้าง JavaScript สามารถใช้หนึ่งในบทบาทของคลาสใน OO ที่อิงกับคลาสดั้งเดิม: ทำหน้าที่เป็นแม่แบบหรือพิมพ์เขียวสำหรับวัตถุใหม่

ตอนนี้ JavaScript เป็นภาษาที่มีประสิทธิภาพมากดังนั้นจึงเป็นเรื่องง่ายที่จะใช้ระบบ OO ในระดับคลาสภายใน JavaScriptหากคุณต้องการ อย่างไรก็ตามคุณควรทำเช่นนี้หากคุณมีความต้องการและไม่เพียงเพราะมันเป็นวิธีที่ Java ทำ


"ถ้าคุณเรียกฟังก์ชันที่มีคีย์เวิร์ดใหม่ฟังก์ชั่นนั้นจะกลายเป็นตัวสร้างและคีย์เวิร์ดนี้จะไม่ชี้ไปที่วัตถุปัจจุบัน แต่แทนที่จะเป็น" ว่างเปล่า "ที่สร้างขึ้นใหม่ หากคุณเรียกใช้ฟังก์ชันที่ไม่มีคีย์เวิร์ดใหม่สิ่งนี้จะอ้างถึงบริบทการโทรโดยค่าเริ่มต้นคือวัตถุกลาง (หน้าต่าง) ในโหมดเข้มงวดไม่ได้กำหนดเป็นค่าเริ่มต้น call, Apply และ bind ใช้การเรียกบริบทเป็นพารามิเตอร์แรก developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/
Elias Hasle

83

คลาส ES2015

ในข้อกำหนด ES2015 คุณสามารถใช้ไวยากรณ์คลาสซึ่งเป็นเพียงแค่วางทับระบบต้นแบบ

class Person {
  constructor(name) {
    this.name = name;
  }
  toString() {
    return `My name is ${ this.name }.`;
  }
}

class Employee extends Person {
  constructor(name, hours) {
    super(name);
    this.hours = hours;
  }
  toString() {
    return `${ super.toString() } I work ${ this.hours } hours.`;
  }
}

ประโยชน์ที่ได้รับ

ประโยชน์หลักคือเครื่องมือวิเคราะห์แบบคงที่พบว่าง่ายต่อการกำหนดเป้าหมายไวยากรณ์นี้ นอกจากนี้ยังง่ายกว่าสำหรับผู้อื่นที่มาจากภาษาที่ใช้ในคลาสเพื่อใช้ภาษาเป็นภาษาพูดได้หลายภาษา

คำเตือน

ระวังข้อ จำกัด ในปัจจุบัน เพื่อให้บรรลุคุณสมบัติส่วนตัวหนึ่งต้องหันไปใช้สัญลักษณ์หรือ WeakMaps ในรุ่นอนาคตจะมีการขยายคลาสเพื่อรวมคุณสมบัติที่หายไปเหล่านี้

สนับสนุน

การสนับสนุนเบราว์เซอร์ยังไม่ดีในขณะนี้ (รองรับเกือบทุกคนยกเว้น IE) แต่คุณสามารถใช้คุณสมบัติเหล่านี้ได้ในขณะนี้ด้วย transpiler เช่นBabelบาเบล

ทรัพยากร


56

{SUPER: SYSTEM}ฉันชอบที่จะใช้ของแดเนียลเอ็กซ์มัวร์ นี่คือวินัยที่ให้ประโยชน์เช่นตัวแปรอินสแตนซ์ที่แท้จริงการสืบทอดจากลักษณะลำดับชั้นของคลาสและตัวเลือกการกำหนดค่า ตัวอย่างด้านล่างแสดงให้เห็นถึงการใช้งานตัวแปรอินสแตนซ์ที่แท้จริงซึ่งฉันเชื่อว่าเป็นข้อได้เปรียบที่ใหญ่ที่สุด หากคุณไม่ต้องการตัวแปรอินสแตนซ์และยินดีที่มีเพียงตัวแปรสาธารณะหรือตัวแปรส่วนตัวก็อาจมีระบบที่ง่ายกว่า

function Person(I) {
  I = I || {};

  Object.reverseMerge(I, {
    name: "McLovin",
    age: 25,
    homeState: "Hawaii"
  });

  return {
    introduce: function() {
      return "Hi I'm " + I.name + " and I'm " + I.age;
    }
  };
}

var fogel = Person({
  age: "old enough"
});
fogel.introduce(); // "Hi I'm McLovin and I'm old enough"

ว้าวนั่นไม่ได้มีประโยชน์มากสำหรับตัวมันเอง แต่ลองดูการเพิ่มคลาสย่อย:

function Ninja(I) {
  I = I || {};

  Object.reverseMerge(I, {
    belt: "black"
  });

  // Ninja is a subclass of person
  return Object.extend(Person(I), {
    greetChallenger: function() {
      return "In all my " + I.age + " years as a ninja, I've never met a challenger as worthy as you...";
    }
  });
}

var resig = Ninja({name: "John Resig"});

resig.introduce(); // "Hi I'm John Resig and I'm 25"

ข้อดีอีกอย่างคือความสามารถในการมีโมดูลและลักษณะสืบทอดตาม

// The Bindable module
function Bindable() {

  var eventCallbacks = {};

  return {
    bind: function(event, callback) {
      eventCallbacks[event] = eventCallbacks[event] || [];

      eventCallbacks[event].push(callback);
    },

    trigger: function(event) {
      var callbacks = eventCallbacks[event];

      if(callbacks && callbacks.length) {
        var self = this;
        callbacks.forEach(function(callback) {
          callback(self);
        });
      }
    },
  };
}

ตัวอย่างของการมีคลาสบุคคลรวมถึงโมดูล bindable

function Person(I) {
  I = I || {};

  Object.reverseMerge(I, {
    name: "McLovin",
    age: 25,
    homeState: "Hawaii"
  });

  var self = {
    introduce: function() {
      return "Hi I'm " + I.name + " and I'm " + I.age;
    }
  };

  // Including the Bindable module
  Object.extend(self, Bindable());

  return self;
}

var person = Person();
person.bind("eat", function() {
  alert(person.introduce() + " and I'm eating!");
});

person.trigger("eat"); // Blasts the alert!

การเปิดเผยข้อมูล: {SUPER: SYSTEM}ผมแดเนียลเอ็กซ์มัวร์และนี่คือของฉัน มันเป็นวิธีที่ดีที่สุดในการกำหนดคลาสใน JavaScript


@DanielXMoore "ตัวแปรอินสแตนซ์จะถูกใช้ร่วมกันระหว่างแต่ละอินสแตนซ์ของคลาส" นั่นไม่ใช่ตัวแปรอินสแตนซ์ซึ่งเป็นตัวแปรแบบสแตติก / คลาส
JAB

2
@JAB ที่ไม่ถูกต้องตัวแปรแบบสแตติก / คลาสจะถูกแชร์ระหว่างอินสแตนซ์ทั้งหมดของคลาส แต่ละอินสแตนซ์มีตัวแปรอินสแตนซ์ของตนเอง
Daniel X Moore

(ใส่อีกวิธีหนึ่งโดยใช้ความหมายปกติของคำว่า "ตัวแปรอินสแตนซ์" ไม่ว่าตัวแปรนั้นจะเป็นตัวแปรมุมฉากถึงระดับความสามารถในการเข้าถึงตัวแปร)
JAB

2
คุณเกือบจะฟังเหมือนซูเปอร์ฮีโร่ที่อ้างสิทธิ์ xD ที่ดีที่สุด
Dadan

วิธีง่ายๆในการกำหนดคลาส Javascript โดยใช้ออบเจ็กต์ javascript: wapgee.com/story/i/203
Ilyas karim

41
var Animal = function(options) {
    var name = options.name;
    var animal = {};

    animal.getName = function() {
        return name;
    };

    var somePrivateMethod = function() {

    };

    return animal;
};

// usage
var cat = Animal({name: 'tiger'});

นี่เป็นวิธีที่ยอดเยี่ยมในการสร้างโครงสร้างวัตถุที่ใช้งานได้โดยไม่ต้องนำเข้าอะไรเลย ฉันใช้ระบบคลาสของ Resig แต่ฉันอาจชอบสิ่งนี้ดีกว่า ขอบคุณ.
ทิม Scollick

29
ปัญหาของวิธีการนี้คือทุกครั้งที่คุณสร้างอินสแตนซ์ Animal ใหม่มันจะกำหนดฟังก์ชั่นใหม่แทนที่จะกำหนดเพียงครั้งเดียวด้วยต้นแบบ
Justin

33

ต่อไปนี้เป็นวิธีการสร้างวัตถุใน javascript ซึ่งฉันใช้ไปแล้ว

ตัวอย่างที่ 1:

obj = new Object();
obj.name = 'test';
obj.sayHello = function() {
    console.log('Hello '+ this.name);
}

ตัวอย่างที่ 2:

obj = {};
obj.name = 'test';
obj.sayHello = function() {
    console.log('Hello '+ this.name);
}
obj.sayHello();

ตัวอย่างที่ 3:

var obj = function(nameParam) {
    this.name = nameParam;
}
obj.prototype.sayHello = function() {
    console.log('Hello '+ this.name);
}

ตัวอย่างที่ 4: ประโยชน์ที่แท้จริงของ Object.create () โปรดอ้างอิง [ลิงค์นี้]

var Obj = {
    init: function(nameParam) {
        this.name = nameParam;
    },
    sayHello: function() {
        console.log('Hello '+ this.name);
    }
};
var usrObj = Object.create(Obj);  // <== one level of inheritance

usrObj.init('Bob');
usrObj.sayHello();

ตัวอย่างที่ 5 (Object.create ของ Crockford แบบกำหนดเอง):

Object.build = function(o) {
   var initArgs = Array.prototype.slice.call(arguments,1)
   function F() {
      if((typeof o.init === 'function') && initArgs.length) {
         o.init.apply(this,initArgs)
      }
   }
   F.prototype = o
   return new F()
}
MY_GLOBAL = {i: 1, nextId: function(){return this.i++}}  // For example

var userB = {
    init: function(nameParam) {
        this.id = MY_GLOBAL.nextId();
        this.name = nameParam;
    },
    sayHello: function() {
        console.log('Hello '+ this.name);
    }
};
var bob = Object.build(userB, 'Bob');  // Different from your code
bob.sayHello();


เพื่อให้คำตอบอัพเดทกับ ES6 / ES2015

คลาสมีการกำหนดเช่นนี้:

class Person {
    constructor(strName, numAge) {
        this.name = strName;
        this.age = numAge;
    }

    toString() {
        return '((Class::Person) named ' + this.name + ' & of age ' + this.age + ')';
    }
}

let objPerson = new Person("Bob",33);
console.log(objPerson.toString());

1
@Justin: โปรดแจ้งให้เราทราบสิ่งที่ไม่ถูกต้อง?
Amol M Kulkarni

ในขณะที่ศึกษาสัญลักษณ์เหล่านี้ฉันก็สะดุดกับสิ่งนี้ set () ตัวอย่างเช่น this.set ('พอร์ต', 3000) ฉันเดาว่านี่ใช้เพื่อตั้งค่าคุณสมบัติพอร์ตสำหรับวัตถุ ถ้าเป็นเช่นนั้นทำไมเราไม่ใช้โดยตรง: {port: 3000} มีเอกสารใดบ้างที่ฉันสามารถรับรายละเอียดเพิ่มเติมได้
adityah

24

ฉันคิดว่าคุณควรอ่านมรดก Prototypalของ Douglas Crockford ใน JavaScriptและClassical Inheritance ใน JavaScriptJavaScript

ตัวอย่างจากหน้าของเขา:

Function.prototype.method = function (name, func) {
    this.prototype[name] = func;
    return this;
};

ผลกระทบ? มันจะช่วยให้คุณเพิ่มวิธีการในวิธีที่สง่างามมากขึ้น

function Parenizor(value) {
    this.setValue(value);
}

Parenizor.method('setValue', function (value) {
    this.value = value;
    return this;
});

ฉันยังแนะนำวิดีโอของเขา: JavaScript ขั้นสูงจาวาสคริปต์ขั้นสูง

คุณสามารถค้นหาวิดีโอเพิ่มเติมในหน้าของเขา: http://javascript.crockford.com/ ในหนังสือ John Reisig คุณสามารถค้นหาตัวอย่างมากมายจากเว็บไซต์ของ Douglas Crockfor


25
มันเป็นแค่ฉันเหรอ? นี่มันยอดเยี่ยมขนาดไหน ฉันจะเรียกคำจำกัดความของฟังก์ชั่นที่เกิดขึ้นจริง'strings'เป็นชื่อหลายสิ่ง แต่สง่างามไม่ใช่หนึ่งในนั้น ...
fgysin reinstate Monica

4
@JAB แต่การสะท้อนกลับเป็นข้อยกเว้นไม่ใช่กฎ ด้วยวิธีการข้างต้นคุณต้องประกาศวิธีการทั้งหมดของคุณด้วยสตริง
Kirk Woll

16

เพราะฉันจะไม่ยอมรับแผนโรงงานของ YUI / Crockford และเพราะฉันต้องการให้สิ่งต่าง ๆ มีอยู่ในตัวและยืดออกได้นี่คือความหลากหลายของฉัน:

function Person(params)
{
  this.name = params.name || defaultnamevalue;
  this.role = params.role || defaultrolevalue;

  if(typeof(this.speak)=='undefined') //guarantees one time prototyping
  {
    Person.prototype.speak = function() {/* do whatever */};
  }
}

var Robert = new Person({name:'Bob'});

ในกรณีที่การทดสอบ typeof นั้นมีลักษณะคล้ายกับวิธีการต้นแบบแรก


ฉันชอบมัน. ฉันมักจะใช้ไวยากรณ์มาตรฐานของ JS เพราะฉันไม่ชอบความคิดในการคัดลอกฟังก์ชั่นลงในแต่ละอินสแตนซ์ของวัตถุ ฉันคิดถึงความงามของการแก้ปัญหาในตัวเองอยู่เสมอและนี่ก็แก้ปัญหาได้ดี
Lukasz Korzybski

1
ไม่แน่ใจ แต่ฉันเข้าใจว่าการกำหนดฟังก์ชันต้นแบบภายในขอบเขต (ค่อนข้างเป็นการปิด) ของฟังก์ชันทำให้หน่วยความจำรั่วเนื่องจากตัวรวบรวมขยะไม่สามารถมาที่นั่นในอินสแตนซ์ของคลาสเหล่านั้น
Sanne

15

หากคุณใช้งานง่ายคุณสามารถหลีกเลี่ยงคำหลัก "ใหม่" ได้ทั้งหมดและใช้วิธีการจากโรงงาน บางครั้งฉันชอบสิ่งนี้เพราะฉันชอบใช้ JSON เพื่อสร้างวัตถุ

function getSomeObj(var1, var2){
  var obj = {
     instancevar1: var1,
     instancevar2: var2,
     someMethod: function(param)
     {  
          //stuff; 
     }
  };
  return obj;
}

var myobj = getSomeObj("var1", "var2");
myobj.someMethod("bla");

ฉันไม่แน่ใจว่าประสิทธิภาพการทำงานของวัตถุขนาดใหญ่จะเป็นอย่างไร


ไม่จำเป็นต้องใช้บรรทัด obj.instancevar1 = var1 เนื่องจากวัตถุภายในจะสามารถเข้าถึงพารามิเตอร์ของ getSomeObj ()
Triptych

ว้าว. นั่นทำให้สมองของฉันเจ็บ แต่ก็มีบางอย่างที่สง่างาม ดังนั้นส่วน "obj.instancevar1 = var1" คือจุดเริ่มต้นของคอนสตรัคเตอร์ฉันคิดว่า?
Karim

เพิ่งเห็นความคิดเห็นของ Triptych ฉันเห็น. ดังนั้นคุณสามารถทำอะไรบางอย่างเช่น "instancevar1: var1" โดยที่วัตถุภายในกำลังถูกสร้างอินสแตนซ์
Karim

ตรง ... เมื่อคุณใช้ {} เพื่อกำหนดวัตถุมันมีการเข้าถึงตัวแปรที่อยู่ในขอบเขต
Sam

10
ด้วยวิธีนี้คุณจะสูญเสียความสามารถในการสืบทอดและเนื่องจากคุณไม่ได้ใช้ obj.prototype.something คุณกำลังกำหนดฟังก์ชั่นทุกครั้งที่คุณใช้วัตถุ = หน่วยความจำมากขึ้นและช้าลง
บาง

12
var Student = (function () {
    function Student(firstname, lastname) {
        this.firstname = firstname;
        this.lastname = lastname;
        this.fullname = firstname + " " + lastname;
    }

    Student.prototype.sayMyName = function () {
        return this.fullname;
    };

    return Student;
}());

var user = new Student("Jane", "User");
var user_fullname = user.sayMyName();

นั่นเป็นวิธีที่ TypeScript รวบรวมคลาสที่มีตัวสร้างเป็น JavaScript


10

วิธีง่ายๆคือ:

function Foo(a) {
  var that=this;

  function privateMethod() { .. }

  // public methods
  that.add = function(b) {
    return a + b;
  };
  that.avg = function(b) {
    return that.add(b) / 2; // calling another public method
  };
}

var x = new Foo(10);
alert(x.add(2)); // 12
alert(x.avg(20)); // 15

เหตุผลthatก็คือthisสามารถผูกกับสิ่งอื่นถ้าคุณให้วิธีการเป็นตัวจัดการเหตุการณ์ดังนั้นคุณจึงบันทึกค่าในระหว่างการเริ่มต้นและใช้มันในภายหลัง

แก้ไข: ไม่ใช่วิธีที่ดีที่สุด แต่เป็นวิธีที่ง่าย ฉันกำลังรอคำตอบที่ดีเช่นกัน!


1
นั่น = โครงสร้างนี้ไม่จำเป็นที่นี่ นอกจากนี้วิธีการเพิ่ม () และ avg () จะถูกคัดลอกสำหรับทุก ๆ "อินสแตนซ์" ของคลาส Foo แทนที่จะแบ่งปันระหว่างกัน
Triptych

1
จำเป็นหรือไม่ (sorta) ในกรณีดังกล่าว แต่ไม่ใช่กรณีง่าย ๆ ที่คุณระบุไว้
Triptych

9

คุณอาจต้องการสร้างประเภทโดยใช้รูปแบบการพับ:

    // Here is the constructor section.
    var myType = function () {
        var N = {}, // Enclosed (private) members are here.
            X = this; // Exposed (public) members are here.

        (function ENCLOSED_FIELDS() {
            N.toggle = false;
            N.text = '';
        }());

        (function EXPOSED_FIELDS() {
            X.count = 0;
            X.numbers = [1, 2, 3];
        }());

        // The properties below have access to the enclosed fields.
        // Careful with functions exposed within the closure of the
        // constructor, each new instance will have it's own copy.
        (function EXPOSED_PROPERTIES_WITHIN_CONSTRUCTOR() {
            Object.defineProperty(X, 'toggle', {
                get: function () {
                    var before = N.toggle;
                    N.toggle = !N.toggle;
                    return before;
                }
            });

            Object.defineProperty(X, 'text', {
                get: function () {
                    return N.text;
                },
                set: function (value) {
                    N.text = value;
                }
            });
        }());
    };

    // Here is the prototype section.
    (function PROTOTYPE() {
        var P = myType.prototype;

        (function EXPOSED_PROPERTIES_WITHIN_PROTOTYPE() {
            Object.defineProperty(P, 'numberLength', {
                get: function () {
                    return this.numbers.length;
                }
            });
        }());

        (function EXPOSED_METHODS() {
            P.incrementNumbersByCount = function () {
                var i;
                for (i = 0; i < this.numbers.length; i++) {
                    this.numbers[i] += this.count;
                }
            };
            P.tweak = function () {
                if (this.toggle) {
                    this.count++;
                }
                this.text = 'tweaked';
            };
        }());
    }());

รหัสที่จะทำให้คุณชนิดที่เรียกว่าชนิดของฉัน ก็จะมีเขตข้อมูลส่วนตัวภายในที่เรียกว่าสลับและข้อความ นอกจากนี้ยังจะมีสมาชิกที่เปิดเผยเหล่านี้: ฟิลด์นับและหมายเลข ; คุณสมบัติสลับ , ข้อความและnumberLength ; วิธีการincrementNumbersByCountและปรับแต่งปรับแต่ง

รูปแบบการพับมีรายละเอียดครบถ้วนที่นี่: รูปแบบการพับ Javascript


3

กอล์ฟสำหรับ @ liammclennan ของคำตอบ

var Animal = function (args) {
  return {
    name: args.name,

    getName: function () {
      return this.name; // member access
    },

    callGetName: function () {
      return this.getName(); // method call
    }
  };
};

var cat = Animal({ name: 'tiger' });
console.log(cat.callGetName());


2

MooTools (Object Oriented เครื่องมือของฉัน) เป็นศูนย์กลางในความคิดของชั้นเรียน คุณสามารถขยายและนำไปใช้กับการสืบทอด

เมื่อเข้าใจจะทำให้จาวาสคริปต์ที่มีประสิทธิภาพนำมาใช้ซ้ำได้อย่างน่าขัน


2

คลาสที่อิงตามวัตถุที่มีการสืบทอด

var baseObject = 
{
     // Replication / Constructor function
     new : function(){
         return Object.create(this);   
     },

    aProperty : null,
    aMethod : function(param){
      alert("Heres your " + param + "!");
    },
}


newObject = baseObject.new();
newObject.aProperty = "Hello";

anotherObject = Object.create(baseObject); 
anotherObject.aProperty = "There";

console.log(newObject.aProperty) // "Hello"
console.log(anotherObject.aProperty) // "There"
console.log(baseObject.aProperty) // null

เรียบง่ายหวานและทำเสร็จแล้ว


1

เป็นฐาน

function Base(kind) {
    this.kind = kind;
}

ห้องเรียน

// Shared var
var _greeting;

(function _init() {
    Class.prototype = new Base();
    Class.prototype.constructor = Class;
    Class.prototype.log = function() { _log.apply(this, arguments); }
    _greeting = "Good afternoon!";
})();

function Class(name, kind) {
    Base.call(this, kind);
    this.name = name;
}

// Shared function
function _log() {
    console.log(_greeting + " Me name is " + this.name + " and I'm a " + this.kind);
}

หนังบู๊

var c = new Class("Joe", "Object");
c.log(); // "Good afternoon! Me name is Joe and I'm a Object"

1

จากตัวอย่างของ Triptych สิ่งนี้อาจจะง่ายกว่า:

    // Define a class and instantiate it
    var ThePerson = new function Person(name, gender) {
        // Add class data members
        this.name = name;
        this.gender = gender;
        // Add class methods
        this.hello = function () { alert('Hello, this is ' + this.name); }
    }("Bob", "M"); // this instantiates the 'new' object

    // Use the object
    ThePerson.hello(); // alerts "Hello, this is Bob"

สิ่งนี้จะสร้างอินสแตนซ์ของวัตถุเดียวเท่านั้น แต่ยังคงมีประโยชน์หากคุณต้องการใส่ชื่อกลุ่มของตัวแปรและเมธอดในคลาส โดยปกติจะไม่มีอาร์กิวเมนต์ "Bob, M" ไปยังผู้สร้างตัวอย่างเช่นหากวิธีการนั้นจะถูกเรียกไปยังระบบที่มีข้อมูลของตัวเองเช่นฐานข้อมูลหรือเครือข่าย

ฉันยังใหม่เกินไปกับ JS เพื่อดูว่าทำไมสิ่งนี้ไม่ใช้prototypeสิ่งนี้


0

JavaScript เป็นแบบเชิงวัตถุแต่แตกต่างจากOOPอื่นอย่างสิ้นเชิงภาษาเช่น Java, C # หรือ C ++ อย่าพยายามเข้าใจอย่างนั้น โยนความรู้เก่านั้นออกไปและเริ่มต้นใหม่อีกครั้ง JavaScript ต้องการความคิดที่แตกต่าง

ฉันขอแนะนำให้รับคู่มือที่ดีหรือบางอย่างในเรื่อง ฉันพบว่าบทเรียนของ ExtJSนั้นดีที่สุดสำหรับฉันแม้ว่าฉันจะไม่ได้ใช้เฟรมเวิร์กก่อนหรือหลังอ่านก็ตาม แต่มันให้คำอธิบายที่ดีเกี่ยวกับสิ่งที่อยู่ในโลกของจาวาสคริปต์ ขออภัยดูเหมือนว่าเนื้อหานั้นได้ถูกลบออกไปแล้ว นี่คือลิงค์สำหรับคัดลอก archive.orgแทน ทำงานวันนี้ : P


2
object-oriented? ฉันคิดว่ามันใช้งานได้
Peter Mortensen

ลิงก์ "บทช่วยสอน ExtJS" ใช้งานไม่ได้
Peter Mortensen

ฉันคิดว่ามันจะอธิบายได้มากกว่านี้เพื่ออธิบายว่าฟังก์ชั่นใน javascript เป็นวัตถุและกฎของวงเล็บเหลี่ยมของ javascript ทำให้แต่ละฟังก์ชั่นปิดกั้นอยู่
mibbit

-1

//new way using this and new
function Persons(name) {
  this.name = name;
  this.greeting = function() {
    alert('Hi! I\'m ' + this.name + '.');
  };
}

var gee=new Persons("gee");
gee.greeting();

var gray=new Persons("gray");
gray.greeting();

//old way
function createPerson(name){
 var obj={};
 obj.name=name;
 obj.greeting = function(){
 console.log("hello I am"+obj.name);
 }; 
  return obj;
}

var gita=createPerson('Gita');
gita.greeting();

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.