如何创建 String 原型克隆并为其分配自定义函数

How to create a String prototype clone and assign custom function to it

我有一个自定义库,其中包含我每次使用 Javascript 时加载的一堆函数。 问题是它们在全局命名空间中工作,有时它们会与其他加载的库(例如 jquery 和 npm 模块)发生冲突。 我的想法是创建自定义原型并使用该原型定义每个变量。 像这样:

let obj = new MyObj ({name: 'John', lastname: 'Doe'});

我已经使用对象和数组创建了自定义原型并且它们工作正常(我想是因为它们已经作为对象工作了)但是我被原始元素如 String 和 Number 所困。

这是我到目前为止写的,试图创建一个自定义字符串原型:

const myStr = function (string) {
    if (!(this instanceof myStr)) { return new myStr(); }
    return this; //or return string?
}
myStr.prototype = Object.create(String.prototype); 
myStr.prototype.constructor = myStr; //or = String?

//custom function assigned to Mystr prototype

Object.defineProperties(myStr.prototype, {
    upp: {
        value: function() {
            return this.toString().toUpperCase();
        }, enumerable: false, writable: false
    }
    //...other custom functions
});

let newString = new myStr('this is my own string');

console.log (newString); 
//it returns 'myStr {}' and not the string passed in function :-(

有没有办法克隆原生原型,向其添加自定义函数,并最终获得一个与原始原生原型完全相同的元素?

自定义原型元素可以利用本机函数和自定义函数。这应该可以防止全局原型污染。

谢谢!

编辑

最后我找到了一个解决方案,据我所知,这是在原始 JS 原型中使用自定义函数并且不与其他模块或库发生冲突的最佳折衷方案。基本上我在每个自定义函数之前添加一个前缀 'my' (但它可以是任何东西)。这不是 'most beautiful thing in the world',但我不知道如何做。

这是字符串的代码:

Object.defineProperties (String.prototype, {
    my: {
        get: function() {
            //it stores string value that is calling functions
            const thisString = this; 
            
            const myStringFunctions = {
                //use get if you want to return a value without parenthesis ()
                get len () {
                    return thisString.length;
                },
                upp: function () {
                    return thisString.toString().toUpperCase();
                }
                //... other custom functions
            };
            
            return myStringFunctions;
        }
    }
});

我用的

console.log ( 'John Doe'.my.upp() ); //JOHN DOE
console.log ( 'John Doe'.my.len ); //8

当然我可以将函数链接在一起,但我必须重复 'custom key'

console.log ( 'John Doe'.my.upp().my.len ); //8

此方法适用于所有Js Prototype。

完成此任务的一种不那么痛苦的方法是利用 class 语法以及免费获得的所有初始化和绑定,尤其是在第一种情况下练习母语 class/type 的子类型,例如 String ...

class MyStr extends String {
  upp () {
    return this.toString().toUpperCase();
  }
}
const newString = new MyStr('this is my own string');

console.log(newString.upp());
console.log(newString+"");

console.log(newString.toString());
console.log(newString.valueOf());
.as-console-wrapper { min-height: 100%!important; top: 0; }

编辑

The provided example code seems to work with strings but shows a strange behavior with arrays and objects. What am I doing wrong here ...

一切正常。人们只需要始终意识到,尤其是对于字符串和数字类型,人们不再处理原始值,而是处理子类型化的 StringNumber 对象。因此,其中一个原因继承了后者的行为。

至于 OP 的子类型数字示例,下一个代码片段提供了本机和自定义数字类型的并行记录...

class MyNum extends Number {}

let customNumber = new MyNum(5);
let nativeNumber = new Number(5);

console.log('test for `valueOf` ... (customNumber + 0) ...', (customNumber + 0));
console.log('test for `valueOf` ... (nativeNumber + 0) ...', (nativeNumber + 0));
console.log('\n');

console.log('test for `toString` ... (customNumber + "0") ...', (customNumber + "0"));
console.log('test for `toString` ... (nativeNumber + "0") ...', (nativeNumber + "0"));
console.log('\n');

console.log('customNumber ...', customNumber, ' // MyNum {5} with straight console logging');
console.log('nativeNumber ...', nativeNumber, ' // Number {5} with straight console logging');
console.log('\n');

console.log('customNumber.valueOf() ...', customNumber.valueOf());
console.log('nativeNumber.valueOf() ...', nativeNumber.valueOf());
console.log('\n');

console.log('(customNumber.valueOf() === customNumber) ?..', (customNumber.valueOf() === customNumber));
console.log('(nativeNumber.valueOf() === nativeNumber) ?..', (nativeNumber.valueOf() === nativeNumber));
console.log('\n');

console.log('(customNumber.valueOf() === (customNumber + 0)) ?..', (customNumber.valueOf() === (customNumber + 0)));
console.log('(nativeNumber.valueOf() === (nativeNumber + 0)) ?..', (nativeNumber.valueOf() === (nativeNumber + 0)));
console.log('\n');

console.log('(customNumber.valueOf() === (nativeNumber + 0)) ?..', (customNumber.valueOf() === (nativeNumber + 0)));
console.log('(nativeNumber.valueOf() === (customNumber + 0)) ?..', (nativeNumber.valueOf() === (customNumber + 0)));
.as-console-wrapper { min-height: 100%!important; top: 0; }

至于JavaScript对象,像Array类型和子类型版本也有一个例子,它记录了两种类型以证明行为没有错要么类型...

class MyArr extends Array {
  first () {
    return this[0];
  }
  last () {
    return this[this.length - 1];
  }
}
let customArray = new MyArr(10, 20, 30, 40);
let nativeArray = new Array(10, 20, 30, 40);

let customArray2 = new MyArr([40, 30, 20, 10]);
let nativeArray2 = new Array([40, 30, 20, 10]);

console.log('test for `valueOf` ... customArray ...', customArray);
console.log('test for `valueOf` ... nativeArray ...', nativeArray);
console.log('\n');
console.log('test for `valueOf` ... customArray2 ...', customArray2);
console.log('test for `valueOf` ... nativeArray2 ...', nativeArray2);
console.log('\n');

console.log('customArray.first() ...', customArray.first());
console.log('customArray.last() ...', customArray.last());
console.log('\n');
console.log('customArray2.first() ...', customArray2.first());
console.log('customArray2.last() ...', customArray2.last());
console.log('\n');

console.log('(customArray + "") ...', (customArray + ""));
console.log('(customArray.toString() === "10,20,30,40") ?..', (customArray.toString() === "10,20,30,40"));
console.log('(customArray.valueOf() === customArray) ?..', (customArray.valueOf() === customArray));
.as-console-wrapper { min-height: 100%!important; top: 0; }