如何";适当地;在JavaScript中创建自定义对象?

如何";适当地;在JavaScript中创建自定义对象?,javascript,Javascript,我想知道创建具有属性和方法的JavaScript对象的最佳方法是什么 我见过一些例子,其中人员使用var self=this,然后在所有函数中使用self.,以确保范围始终正确 然后,我看到了使用.prototype添加属性的示例,而其他人则使用内联方式 有人能给我一个带有一些属性和方法的JavaScript对象的适当例子吗?当一个人在构造函数调用过程中使用关闭“this”的技巧时,是为了编写一个函数,该函数可以被其他不想调用对象方法的对象用作回调。这与“使范围正确”无关 下面是一个普通的Jav

我想知道创建具有属性和方法的JavaScript对象的最佳方法是什么

我见过一些例子,其中人员使用
var self=this
,然后在所有函数中使用
self.
,以确保范围始终正确

然后,我看到了使用
.prototype
添加属性的示例,而其他人则使用内联方式


有人能给我一个带有一些属性和方法的JavaScript对象的适当例子吗?

当一个人在构造函数调用过程中使用关闭“this”的技巧时,是为了编写一个函数,该函数可以被其他不想调用对象方法的对象用作回调。这与“使范围正确”无关

下面是一个普通的JavaScript对象:

function MyThing(aParam) {
    var myPrivateVariable = "squizzitch";

    this.someProperty = aParam;
    this.useMeAsACallback = function() {
        console.log("Look, I have access to " + myPrivateVariable + "!");
    }
}

// Every MyThing will get this method for free:
MyThing.prototype.someMethod = function() {
    console.log(this.someProperty);
};
Foo.publicStaticMethod(); //calling a static method
var test = new Foo();     //instantiation
test.publicMethod();      //calling a method

你可能会从阅读JavaScript的文章中得到很多东西。也很精彩。祝你好运

您也可以这样做,使用以下结构:

function createCounter () {
    var count = 0;

    return {
        increaseBy: function(nb) {
            count += nb;
        },
        reset: function {
            count = 0;
        }
    }
}
然后:

var counter1 = createCounter();
counter1.increaseBy(4);
道格拉斯·克罗克福德(Douglas Crockford)在好的部分广泛地讨论了这个话题。他建议避免使用new操作符来创建新对象。相反,他建议创建定制的构造函数。例如:

var mammal = function (spec) {     
   var that = {}; 
   that.get_name = function (  ) { 
      return spec.name; 
   }; 
   that.says = function (  ) { 
      return spec.saying || ''; 
   }; 
   return that; 
}; 

var myMammal = mammal({name: 'Herb'});
在Javascript中,函数是一个对象,可以与new操作符一起用于构造对象。按照惯例,打算用作构造函数的函数以大写字母开头。你经常会看到这样的事情:

function Person() {
   this.name = "John";
   return this;
}

var person = new Person();
alert("name: " + person.name);**

如果在实例化一个新对象时忘记使用new操作符,您得到的是一个普通的函数调用,它绑定到全局对象而不是新对象。

我相当频繁地使用这种模式-我发现它在我需要时给了我相当大的灵活性。在使用中,它与Java风格的类非常相似

var Foo = function()
{

    var privateStaticMethod = function() {};
    var privateStaticVariable = "foo";

    var constructor = function Foo(foo, bar)
    {
        var privateMethod = function() {};
        this.publicMethod = function() {};
    };

    constructor.publicStaticMethod = function() {};

    return constructor;
}();
它使用一个匿名函数,在创建时调用该函数,并返回一个新的构造函数。因为匿名函数只调用一次,所以可以在其中创建私有静态变量(它们位于闭包内,对类的其他成员可见)。构造器函数基本上是一个标准的Javascript对象,您可以在其中定义私有属性,公共属性附加到
这个
变量

基本上,这种方法将Crockfordian方法与标准Javascript对象相结合,以创建一个更强大的类

您可以像使用任何其他Javascript对象一样使用它:

function MyThing(aParam) {
    var myPrivateVariable = "squizzitch";

    this.someProperty = aParam;
    this.useMeAsACallback = function() {
        console.log("Look, I have access to " + myPrivateVariable + "!");
    }
}

// Every MyThing will get this method for free:
MyThing.prototype.someMethod = function() {
    console.log(this.someProperty);
};
Foo.publicStaticMethod(); //calling a static method
var test = new Foo();     //instantiation
test.publicMethod();      //calling a method

在JavaScript中实现类和实例有两种模型:原型方法和闭包方法。两者都有优点和缺点,并且有很多扩展的变体。许多程序员和库都有不同的方法和类处理实用程序函数来掩盖语言中一些丑陋的部分

结果是,在混合公司中,您将有一堆元类,所有元类的行为都略有不同。更糟糕的是,大多数JavaScript教程材料都很糟糕,并且提供了某种折衷方案来覆盖所有基础,这让您非常困惑。(作者可能也感到困惑。JavaScript的对象模型与大多数编程语言非常不同,而且在许多地方设计得很糟糕。)

让我们从原型方式开始。这是您可以获得的最原始的JavaScript:代码开销最小,instanceof将处理此类对象的实例

function Shape(x, y) {
    this.x= x;
    this.y= y;
}
我们可以通过将方法写入此构造函数的
prototype
查找中,向
newshape
创建的实例添加方法:

Shape.prototype.toString= function() {
    return 'Shape at '+this.x+', '+this.y;
};
现在来对它进行子类化,尽可能多地调用JavaScript进行子类化。我们通过完全替换怪异的魔法
prototype
属性来实现这一点:

function Circle(x, y, r) {
    Shape.call(this, x, y); // invoke the base class's constructor function to take co-ords
    this.r= r;
}
Circle.prototype= new Shape();
在向其添加方法之前:

Circle.prototype.toString= function() {
    return 'Circular '+Shape.prototype.toString.call(this)+' with radius '+this.r;
}
这个例子会起作用,你会在很多教程中看到类似的代码。但是,这个
newshape()
太难看了:我们正在实例化基类,尽管没有创建实际的形状。在这种简单的情况下,它恰好可以工作,因为JavaScript非常松散:它允许传入零个参数,在这种情况下,
x
y
变成
未定义的
,并被分配给原型的
this.x
this.y
。如果构造函数正在做任何更复杂的事情,那么它就会一败涂地

因此,我们需要做的是找到一种方法来创建一个原型对象,其中包含我们想要在类级别上使用的方法和其他成员,而无需调用基类的构造函数。要做到这一点,我们必须开始编写助手代码。这是我所知道的最简单的方法:

function subclassOf(base) {
    _subclassOf.prototype= base.prototype;
    return new _subclassOf();
}
function _subclassOf() {};
这将基类的原型中的成员转移到一个新的构造函数,该构造函数不做任何事情,然后使用该构造函数。现在我们可以简单地写下:

function Circle(x, y, r) {
    Shape.call(this, x, y);
    this.r= r;
}
Circle.prototype= subclassOf(Shape);
而不是
新形状()
错误。我们现在有了一组可接受的基本体来构建类

<> P>在这个模型下我们可以考虑一些改进和扩展。例如,这里有一个语法上的sugar版本:

Function.prototype.subclass= function(base) {
    var c= Function.prototype.subclass.nonconstructor;
    c.prototype= base.prototype;
    this.prototype= new c();
};
Function.prototype.subclass.nonconstructor= function() {};

...

function Circle(x, y, r) {
    Shape.call(this, x, y);
    this.r= r;
}
Circle.subclass(Shape);
这两个版本都有一个缺点,即构造函数不能被继承,因为在许多语言中都是这样。因此,即使您的子类没有向构造过程添加任何内容,它也必须记住使用基所需的任何参数调用基构造函数。这可以使用
apply
略微自动化,但您仍然必须写出:

function Point() {
    Shape.apply(this, arguments);
}
Point.subclass(Shape);
因此,一个常见的扩展是将初始化内容分解为它自己的函数,而不是构造函数本身。然后,此函数就可以从基继承了:

function Shape() { this._init.apply(this, arguments); }
Shape.prototype._init= function(x, y) {
    this.x= x;
    this.y= y;
};

function Point() { this._init.apply(this, arguments); }
Point.subclass(Shape);
// no need to write new initialiser for Point!
现在,我们为每个类提供了相同的构造函数样板。也许我们可以把它移到它自己的helper函数中,这样我们就不必一直键入它,例如,不必键入
Func
Circle= Shape.makeSubclass({
    _init: function(x, y, z) {
        Shape.prototype._init.call(this, x, y);
        this.r= r;
    },
    ...
});
function Shape(x, y) {
    var that= this;

    this.x= x;
    this.y= y;

    this.toString= function() {
        return 'Shape at '+that.x+', '+that.y;
    };
}

function Circle(x, y, r) {
    var that= this;

    Shape.call(this, x, y);
    this.r= r;

    var _baseToString= this.toString;
    this.toString= function() {
        return 'Circular '+_baseToString(that)+' with radius '+that.r;
    };
};

var mycircle= new Circle();
var ts= mycircle.toString;
alert(ts());
setTimeout(function() {
    mycircle.move(1, 1);
}, 1000);
setTimeout(mycircle.move.bind(mycircle, 1, 1), 1000);
function Shape(x, y) {
    var that= {};

    that.x= x;
    that.y= y;

    that.toString= function() {
        return 'Shape at '+that.x+', '+that.y;
    };

    return that;
}

function Circle(x, y, r) {
    var that= Shape(x, y);

    that.r= r;

    var _baseToString= that.toString;
    that.toString= function() {
        return 'Circular '+_baseToString(that)+' with radius '+r;
    };

    return that;
};

var mycircle= Circle(); // you can include `new` if you want but it won't do anything
// Build-Reveal

var person={
create:function(_name){ // 'constructor'
                        //  prevents direct instantiation 
                        //  but no inheritance
    return (function() {

        var name=_name||"defaultname";  // private variable

        // [some private functions]

        function getName(){
            return name;
        }

        function setName(_name){
            name=_name;
        }

        return {    // revealed functions
            getName:getName,    
            setName:setName
        }
    })();
   }
  }

  // … no (instantiated) person so far …

  var p=person.create(); // name will be set to 'defaultname'
  p.setName("adam");        // and overwritten
  var p2=person.create("eva"); // or provide 'constructor parameters'
  alert(p.getName()+":"+p2.getName()); // alerts "adam:eva"
function outer(outerArg) {
    return inner(innerArg) {
        return innerArg + outerArg; //the scope chain is composed of innerArg and outerArg from the outer context 
    }
}
public class Calculator {
    public property VAT { get; private set; }
    public Calculator(int vat) {
        this.VAT = vat;
    }
    public int Calculate(int price) {
        return price * this.VAT;
    }
}
function calculator(vat) {
    return function(item) {
        return item * vat;
    }
}
var calculate = calculator(1.10);
var jsBook = 100; //100$
calculate(jsBook); //110
//Constructor Pattern
function Person(name, age, job){
 this.name = name;
 this.age = age;
 this.job = job;
 this.doSomething = function(){
    alert('I am Happy');
}
}
var person1 = new Person('Arv', 30, 'Software');
person1.name //Arv
var Person = function (lastname, age, job){
this.name = name;
this.age = age;
this.job = job;
this.changeName = function(name){
this.lastname = name;
}
}
var myWorker = new Person('Adeola', 23, 'Web Developer');
myWorker.changeName('Timmy');

console.log("New Worker" + myWorker.lastname);
class Shape {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }

    toString() {
        return `Shape at ${this.x}, ${this.y}`;
    }
}
class Circle extends Shape {
    constructor(x, y, r) {
        super(x, y);
        this.r = r;
    }

    toString() {
        let shapeString = super.toString();
        return `Circular ${shapeString} with radius ${this.r}`;
    }
}
var Foo = (function () {
    function Foo() {
        this._bar = false;
    }
    Object.defineProperty(Foo.prototype, "bar", {
        get: function () {
            return this._bar;
        },
        set: function (theBar) {
            this._bar = theBar;
        },
        enumerable: true,
        configurable: true
    });
    Foo.prototype.toTest = function () {
        alert("my value is " + this.bar);
    };
    return Foo;
}());

// test instance
var test = new Foo();
test.bar = true;
test.toTest();
    function Person(obj) {
    'use strict';
    if (typeof obj === "undefined") {
        this.name = "Bob";
        this.age = 32;
        this.company = "Facebook";
    } else {
        this.name = obj.name;
        this.age = obj.age;
        this.company = obj.company;
    }

}

Person.prototype.print = function () {
    'use strict';
    console.log("Name: " + this.name + " Age : " + this.age + " Company : " + this.company);
};

var p1 = new Person({name: "Alex", age: 23, company: "Google"});
p1.print();
var Klass = function Klass() {
    var thus = this;
    var somePublicVariable = x
      , somePublicVariable2 = x
      ;
    var somePrivateVariable = x
      , somePrivateVariable2 = x
      ;

    var privateMethod = (function p() {...}).bind(this);

    function publicMethod() {...}

    // export precepts
    this.var1 = somePublicVariable;
    this.method = publicMethod;

    return this;
};
var Super = function Super() {
    ...
    this.inherited = true;
    ...
};
var Klass = function Klass() {
    ...
    // export precepts
    Super.apply(this);  // extends this with property `inherited`
    ...
};
var Model = function Model(options) {
    var options = options || {};

    this.id = options.id || this.id || -1;
    this.string = options.string || this.string || "";
    // ...

    return this;
};
var model = new Model({...});
var updated = Model.call(model, { string: 'modified' });
(model === updated === true);  // > true
var Singleton = new (function Singleton() {
    var INSTANCE = null;

    return function Klass() {
        ...
        // export precepts
        ...

        if (!INSTANCE) INSTANCE = this;
        return INSTANCE;
    };
})();
var a = new Singleton();
var b = new Singleton();
(a === b === true);  // > true
var klass = new (function Klass(Base) {
    ...
    // export precepts
    Base.apply(this);  //
    this.override = x;
    ...
})(Super);
var klass = Super.apply({
    override: x
});
Klass.prototype = new Super();
// OR
Klass.prototype = new (function Base() {
    ...
    // export precepts
    Base.apply(this);
    ...
})(Super);
// OR
Klass.prototype = Super.apply({...});
// OR
Klass.prototype = {
    method: function m() {...}
};
Klass.prototype.method = function m() {...};