可重复使用的JavaScript对象,原型和范围(reusable javascript objec

2019-08-31 09:11发布

MyGlobalObject;

function TheFunctionICanUseRightAwaySingleForAllInstansesAndWithoutInstanse() {
    function() {
        alert('NO CONSTRUCTOR WAS CALLED');
    }
};

长命名的功能必须是可调用从MyGlobalObject ,而这又必须作为一个全球性的(到window中的所有次)变量脚本加载后。 它应该支持符合最新标准的可扩展性。

我在如何建立JS基础的应用程序(几乎100%JS)建筑困境。

我们需要一个对象,即window.MyObject (比如模块,像jQuery),所以

它可以与创建

VAR1

 var MyGlobalObjConstructor = function(){
     this.GlobalFunctionInObject = function(){
        alert('called with MyGlobalObj.GlobalFunctionInObject()');
        }        
};
window.MyGlobalObj = new MyGlobalObjConstructor();    

MyGlobalObj扩展? 我可以创建子对象,其将继承的当前状态MyGlobalObj (扩展功能/性能MyGlobalObj.NewFunc如)? 使用原型(VAR3)之间的主要区别是什么?

通过GlobaldFunction我的意思是所有的初始化/实例化(可能instantializable)情况下,单一实例..

VAR2

var MyGlobalObj = {
    GlobalFunctionInObject: function...
    GlobalFunctionInObject2: function...
};
MyGlobalObj.GlobalFunctionInObject();
// here I lose all hierarchy elements, no prototype, 
// can I use GlobalFunctionInObject2 in GlobalFunctionInObject?

VAR3

var MyGlobalConstuctor = function(){} // already 'well-formed' object
MyGlobalConstuctor.prototype.GlobalFunctionInObject = function...
};
var MyGlobalObj = new MyGlobalConstuctor();

// so I'm sceptical to NEW, because I have ALREADY wrote my functions 
// which I expect to be in memory, single instance of each of them, 
// so creating MyObject2,3,4 with NEW MyGC() makes no sense to me.
// DO I REALLY HAVE TO USE "MyGlobalConstuctor.prototype." FOR EACH FUNCTION?!!!!

什么是定义的区别MyGlobalObj的功能和作为对象(FUNC的或VAR2结果)?

OR VAR4?

我在Chrome调试器看到两个原型和__proto__特殊领域。 我读过,这是确定的,但他们为什么不保存在一个单一的原型?

那么,什么是实现正确的/最佳方式window.MyObject ,所以人们可以MyObject.MyFunction(); 什么是变体1 2和3的差异(PRO /禁忌)?

Answer 1:

Variation 1 - Mixin

function SomeType() {
    var priv = "I'm private";
    this.publ = "I'm public";
    this.action = function() {
        return priv + this.publ;
    };
}

var obj = new SomeType();

使用这种方法,你正在创建每次通话时间一个新的对象new SomeType()造就了其所有的方法和添加所有这些方法的新对象。 每当你创建一个对象。

优点

  • 它看起来像经典的继承,所以很容易理解到Java的C#-C ++ - 等人。
  • 它可以为每个实例私有变量,因为你有一个功能关闭每个您创建的每个对象
  • 它允许多重继承,也称为Twitter的混入或官能混入
  • obj instanceof SomeType将返回true

缺点

  • 它消耗较多的内存作为您创造更多的对象,因为与每个对象要创建一个新的关闭和重新创建每个它的方法。
  • 私有财产private ,不protected ,亚型不能访问它们
  • 要知道没有简单的方法,如果一个对象具有某种类型的超类。

遗产

function SubType() {
    SomeType.call(this);
    this.newMethod = function() {
        // can't access priv
        return this.publ;
    };
}

var child = new SubType();

child instanceof SomeType将返回false表示没有其他办法可以知道,如果孩子有SOMETYPE方法不是看它是否有逐一。

变化2 - 对象文本与原型

var obj = {
    publ: "I'm public",
    _convention: "I'm public too, but please don't touch me!",
    someMethod: function() {
        return this.publ + this._convention;
    }
};

在这种情况下,要创建一个对象。 如果你打算只需要一个这种类型的实例也可以是最好的解决办法。

优点

  • 它的快速和容易理解。
  • 高性能

缺点

  • 没有隐私,每个属性是公共的。

遗产

您可以继承对象原型设计。

var child = Object.create(obj);
child.otherMethod = function() {
    return this._convention + this.publ;
};

如果你是在一个旧的浏览器,你将需要garantee Object.create工作:

if (!Object.create) {
    Object.create = function(obj) {
        function tmp() { }
        tmp.prototype = obj;
        return new tmp;
    };
}

要知道,如果一个对象是另一个原型可以使用

obj.isPrototypeOf(child); // true

变化3 - 构造格局

UPDATE:这是一种模式ES6类的糖语法 。 如果您使用ES6类你是以下引擎盖下这种模式。

class SomeType {
    constructor() {
        // REALLY important to declare every non-function property here
        this.publ = "I'm public";
        this._convention = "I'm public too, but please don't touch me!";
    }
    someMethod() {
        return this.publ + this._convention;
    }
}

class SubType extends SomeType {
    constructor() {
        super(/* parent constructor parameters here */);
        this.otherValue = 'Hi';
    }
    otherMethod() {
        return this._convention + this.publ + this.otherValue;
    }
}

function SomeType() {
    // REALLY important to declare every non-function property here
    this.publ = "I'm public";
    this._convention = "I'm public too, but please don't touch me!";
}

SomeType.prototype.someMethod = function() {
    return this.publ + this._convention;
};

var obj = new SomeType();

您可以重新分配将每一种方法,如果你不继承的原型insteadd并记住constructor属性重新分配:

SomeType.prototype = {
    constructor: SomeType,
    someMethod = function() {
        return this.publ + this._convention;
    }
};

或者使用_.extend或$ .extend,如果你在你的页面下划线或jQuery的

_.extend(SomeType.prototype, {
    someMethod = function() {
        return this.publ + this._convention;
    }
};

new引擎盖下的关键字只是做到这一点:

function doNew(Constructor) {
    var instance = Object.create(Constructor.prototype);
    instance.constructor();
    return instance;
}

var obj = doNew(SomeType);

你有什么比没有任何方法的功能; 它只是有一个prototype与功能的列表属性,在new运营手段来创建一个新的对象,并使用该函数的原型( Object.create )和constructor财产初始化。

优点

  • 高性能
  • 原型链将让你知道,如果一个物体从某种类型的继承

缺点

  • 两步继承

遗产

function SubType() {
    // Step 1, exactly as Variation 1
    // This inherits the non-function properties
    SomeType.call(this);
    this.otherValue = 'Hi';
}

// Step 2, this inherits the methods
SubType.prototype = Object.create(SomeType.prototype);
SubType.prototype.otherMethod = function() {
    return this._convention + this.publ + this.otherValue;
};

var child = new SubType();

你可能认为它看起来像变2的超集......你会是正确的。 这就像变2一样,但一个初始化函数(构造函数);

child instanceof SubTypechild instanceof SomeType将同时返回true

好奇心:引擎盖下instanceof运算符的作用是

function isInstanceOf(obj, Type) {
    return Type.prototype.isPrototypeOf(obj);
}

变化4 -覆盖__proto__

当你这样做Object.create(obj)引擎盖下它

function fakeCreate(obj) {
    var child = {};
    child.__proto__ = obj;
    return child;
}

var child = fakeCreate(obj);

__proto__属性直接修改对象的隐藏[Prototype]属性。 因为这可以打破JavaScript的行为,它不是标准。 和标准的方式是优选的( Object.create )。

优点

  • 快速,高性能

缺点

  • 非标
  • 危险的; 你不能因为一个HashMap __proto__键可以改变对象的原型

遗产

var child = { __proto__: obj };
obj.isPrototypeOf(child); // true

如何处理问题

1. VAR1:在SomeType.call(这)会发生什么? 是“呼叫”特殊功能?

哦,是的,函数是对象,使他们有方法,我会提到三: .CALL() , 。适用()和.bind()

当你在一个函数中使用.CALL(),你可以通过一个额外的参数, 背景 ,价值this里面的功能,例如:

var obj = {
    test: function(arg1, arg2) {
        console.log(this);
        console.log(arg1);
        console.log(arg2);
    }
};

// These two ways to invoke the function are equivalent

obj.test('hi', 'lol');

// If we call fn('hi', 'lol') it will receive "window" as "this" so we have to use call.
var fn = obj.test;
fn.call(obj, 'hi', 'lol');

所以,当我们做SomeType.call(this)我们传递对象this运作SomeCall ,你还记得这个函数方法添加到反对this

2. VAR3:你的“真正定义属性”你的意思是,如果我在函数中使用它们? 它是一个约定? 因为越来越this.newProperty而不会被在与其他构件的功能相同的级别上定义是没有问题的。

我的意思是任何财产的对象将不是必须在构造函数中定义的,而不是在原型的功能,否则你将面临更加混乱JS的问题之一。 你可以在这里看到它 ,但它是这个问题的焦点之外。

3. VAR3:如果我不重新分配的构造会发生什么?

其实你可能看不到的差异,这是什么使得它一个危险的错误。 每个函数的原型对象有一个constructor属性,以便您可以从一个实例访问的构造。

function A() { }

// When you create a function automatically, JS does this:
// A.prototype = { constructor: A };

A.prototype.someMethod = function() {
    console.log(this.constructor === A); // true
    this.constructor.staticMethod();
    return new this.constructor();  
};

A.staticMethod = function() { };

因为不是每个人都知道这件事,但有时它可以帮助它不是最好的做法。 但是,如果你重新分配原型...

A.prototype = {
    someMethod = function() {
        console.log(this.constructor === A); // false
        console.log(this.constructor === Object); // true
        this.constructor.staticMethod();
        return new this.constructor();  
    }
};

A.prototype是一个新的对象,的实例Object比原型Object.prototypeObject.prototype.constructorObject 。 令人困惑的,对不对? :P

所以,如果你覆盖原型,并不会复位“构造”特性,它会参考Object ,而不是A ,如果你尝试使用“构造”属性来访问一些静态方法,你可能会疯了。



Answer 2:

我通常解决与返回与功能属性的对象:

var newCat = function (name) {
return {name: name, purr: function () {alert(name + ' purrs')}};
};

var myCat = newCat('Felix');
myCat.name; // 'Felix'
myCat.purr(); // alert fires

您可以通过调用newCat功能具有继承和扩展你的对象:

var newLion = function (name) {
    var lion = newCat(name);
    lion.roar = function () {
        alert(name + ' roar loudly');
    }
    return lion;
}

如果你想有一个全球性的猫对象:

var cats = (function () {

var newCat = function (name) {
    return {
        name: name,
        purr: function () {
            alert(name + ' is purring')
        }
    };
};

return {
    newCat: newCat
};
}());

现在,您可以拨打:

var mySecondCat = cats.newCat('Alice');


文章来源: reusable javascript objects, prototypes and scope