我喜欢在目前正在从事的大型项目中使用OOP。我需要用JavaScript创建几个类,但是,如果我没有记错的话,至少有两种方法可以做到这一点。语法是什么,为什么要用这种方式呢?
我想避免使用第三方库-至少在一开始。
在寻找其他答案时,我找到了文章“ 使用JavaScript进行面向对象的编程”,第一部分:继承-文档JavaScript,该文章讨论了JavaScript中的面向对象的编程。有更好的继承方法吗?
我喜欢在目前正在从事的大型项目中使用OOP。我需要用JavaScript创建几个类,但是,如果我没有记错的话,至少有两种方法可以做到这一点。语法是什么,为什么要用这种方式呢?
我想避免使用第三方库-至少在一开始。
在寻找其他答案时,我找到了文章“ 使用JavaScript进行面向对象的编程”,第一部分:继承-文档JavaScript,该文章讨论了JavaScript中的面向对象的编程。有更好的继承方法吗?
Answers:
这是无需使用任何外部库即可完成的方法:
// 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中的类功能。您将至少要签出Prototype和jQuery。
确定其中哪一个是“最佳”是在Stack Overflow上发起一场神圣战争的好方法。如果您正着手进行一个较大的JavaScript大型项目,那么绝对值得学习流行的库并按自己的方式去做。我是一个原型人,但是Stack Overflow似乎倾向于jQuery。
至于只有“一种方法”,而没有对外部库的任何依赖,我写的方式就差不多了。
在JavaScript中定义类的最佳方法是不定义类。
说真的
有几种不同的面向对象风格,其中一些是:
可能还有其他我不认识的人。
JavaScript实现了基于原型的OO。在基于原型的OO中,通过复制其他对象(而不是从类模板实例化)来创建新对象,并且方法直接存在于对象中而不是类中。继承是通过委托完成的:如果对象没有方法或属性,则在其原型(即从其克隆的对象)上查找该对象,然后在该原型的原型上进行查找,依此类推。
换句话说:没有类。
JavaScript实际上对该模型做了一个很好的调整:构造函数。可以说,不仅可以通过复制现有对象来创建对象,还可以“凭空”构造它们。如果使用new
关键字调用一个函数,则该函数将成为构造函数,而该this
关键字将不会指向当前对象,而是指向一个新创建的“空”对象。因此,您可以根据自己的喜好配置对象。这样,JavaScript构造函数就可以在传统的基于类的OO中担当类的角色之一:充当新对象的模板或蓝图。
现在,JavaScript是一种非常强大的语言,因此,如果需要,在JavaScript中实现基于类的OO系统非常容易。但是,只有在确实有需要时才应该这样做,而不仅仅是因为Java就是这样做的。
在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.`;
}
}
主要优点是静态分析工具发现更容易针对此语法。对于其他来自基于类的语言的人,使用该语言作为多语言也更容易。
警惕其当前的局限性。要获得私有属性,必须使用Symbols或WeakMaps。在将来的版本中,很可能会将类扩展为包括这些缺少的功能。
浏览器支持是不是现在(通过IE除外几乎每个人都支持)很不错,但你可以像现在transpiler使用这些功能巴贝尔。
我更喜欢使用Daniel X. Moore的{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);
});
}
},
};
}
具有人员类的示例包括可绑定模块。
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!
披露:我是Daniel X. Moore,这是我的{SUPER: SYSTEM}
。这是在JavaScript中定义类的最佳方法。
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'});
以下是迄今为止我在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(自定义的Crockford's Object.create):
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();
一个类的定义如下:
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());
我想你应该读道格拉斯Crockford的原型继承在JavaScript和JavaScript中的经典传承。
他页面上的示例:
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;
});
我还推荐他的视频: Advanced JavaScript。
您可以在他的页面上找到更多视频:http : //javascript.crockford.com/在John Reisig的书中,您可以从Douglas Crockfor的网站上找到许多示例。
'strings'
名称来调用函数定义,但是很多事情都不是优雅的……
因为我不会接受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测试是在第一个方法原型上进行的
如果您只是为了简单起见,则可以完全避免使用“ new”关键字,而只需使用工厂方法即可。有时候,我更喜欢这样做,因为我喜欢使用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");
不过,我不确定大型对象的性能会受到什么影响。
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的方式。
简单的方法是:
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
如果将方法作为事件处理程序提供则可以绑定到其他对象,因此可以在实例化过程中保存该值并在以后使用。
编辑:这绝对不是最好的方法,只是一种简单的方法。我也在等待好的答案!
您可能想使用折叠模式创建类型:
// 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';
};
}());
}());
该代码将为您提供一个名为myType的类型。它将具有称为切换和文本的内部私有字段。它还将具有以下暴露的成员:字段数和数字;属性切换,文本和数字长度 ; 方法crementNumbersByCount和调整。
折叠模式在此处进行了详细说明: Javascript折叠模式
具有继承的基于对象的类
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
简单,贴心,可以完成。
一个基地
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"
根据三联画的示例,这甚至可能更简单:
// 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
。
JavaScript是面向对象的,但与Java,C#或C ++ 等其他OOP语言完全不同。不要试图那样理解它。把旧知识扔掉,重新开始。JavaScript需要不同的想法。
我建议您获得一本好的手册或有关该主题的内容。我自己发现ExtJS教程最适合我,尽管我在阅读框架之前或之后都没有使用过该框架。但这确实对JavaScript世界中的什么给出了很好的解释。抱歉,该内容似乎已被删除。这是指向archive.org复制的链接。今天工作。:P
//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();