]> git.kaiwu.me - njs.git/commitdiff
Added Object.assign().
authorAlexander Mazyrin <algoritmist1618@gmail.com>
Sat, 12 Oct 2019 13:23:25 +0000 (16:23 +0300)
committerAlexander Mazyrin <algoritmist1618@gmail.com>
Sat, 12 Oct 2019 13:23:25 +0000 (16:23 +0300)
src/njs_object.c
src/njs_value.c
src/test/njs_unit_test.c

index 26c051def1681b56ef89b757b44833919d99c2e9..76d8698ec8f0676343220b985ea46fb94f2bd321 100644 (file)
@@ -1637,6 +1637,67 @@ njs_object_is_extensible(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
 }
 
 
+static njs_int_t
+njs_object_assign(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+    njs_index_t unused)
+{
+    uint32_t              i, j, length;
+    njs_int_t             ret;
+    njs_array_t           *names;
+    njs_value_t           *key, *source, *value, setval;
+    njs_object_prop_t     *prop;
+    njs_property_query_t  pq;
+
+    value = njs_arg(args, nargs, 1);
+
+    ret = njs_value_to_object(vm, value);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return ret;
+    }
+
+    for (i = 2; i < nargs; i++) {
+        source = &args[i];
+
+        names = njs_value_own_enumerate(vm, source, NJS_ENUM_KEYS, 1);
+        if (njs_slow_path(names == NULL)) {
+            return NJS_ERROR;
+        }
+
+        length = names->length;
+
+        for (j = 0; j < length; j++) {
+            key = &names->start[j];
+
+            njs_property_query_init(&pq, NJS_PROPERTY_QUERY_GET, 1);
+
+            ret = njs_property_query(vm, &pq, source, key);
+            if (njs_slow_path(ret != NJS_OK)) {
+                return NJS_ERROR;
+            }
+
+            prop = pq.lhq.value;
+            if (!prop->enumerable) {
+                continue;
+            }
+
+            ret = njs_value_property(vm, source, key, &setval);
+            if (njs_slow_path(ret != NJS_OK)) {
+                return NJS_ERROR;
+            }
+
+            ret = njs_value_property_set(vm, value, key, &setval);
+            if (njs_slow_path(ret != NJS_OK)) {
+                return NJS_ERROR;
+            }
+        }
+    }
+
+    vm->retval = *value;
+
+    return NJS_OK;
+}
+
+
 /*
  * The __proto__ property of booleans, numbers and strings primitives,
  * of objects created by Boolean(), Number(), and String() constructors,
@@ -1908,6 +1969,15 @@ static const njs_object_prop_t  njs_object_constructor_properties[] =
         .writable = 1,
         .configurable = 1,
     },
+
+    /* Object.assign(). */
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("assign"),
+        .value = njs_native_function(njs_object_assign, 2),
+        .writable = 1,
+        .configurable = 1,
+    },
 };
 
 
index a716f2dba25ade15fc1f8adb57caaddbbd470683..8d4756cbf66c91ceedd0e670509cb16481e02eb4 100644 (file)
@@ -1186,9 +1186,8 @@ njs_value_to_object(njs_vm_t *vm, njs_value_t *value)
         return NJS_ERROR;
     }
 
-    if (njs_is_object(value)) {
+    if (njs_fast_path(njs_is_object(value))) {
         return NJS_OK;
-
     }
 
     if (njs_is_primitive(value)) {
index 0872dcc6f3650bc41af986e691cfc367a882de7d..8780e34363fc183b4ad69e9b2e8163175ce1ad53 100644 (file)
@@ -14531,6 +14531,71 @@ static njs_unit_test_t  njs_test[] =
     { njs_str("export"),
       njs_str("SyntaxError: Illegal export statement in 1") },
 
+    { njs_str("Object.assign(undefined)"),
+      njs_str("TypeError: cannot convert null or undefined to object") },
+
+    { njs_str("Object.assign(null)"),
+      njs_str("TypeError: cannot convert null or undefined to object") },
+
+    { njs_str("Object.assign({x:123}).toString()"),
+      njs_str("[object Object]") },
+
+    { njs_str("Object.assign({x:123}).x"),
+      njs_str("123") },
+
+    { njs_str("Object.assign(true)"),
+      njs_str("true") },
+
+    { njs_str("Object.assign(123)"),
+      njs_str("123") },
+
+    { njs_str("var o1 = {a:1, b:1, c:1}; var o2 = {b:2, c:2}; "
+                 "var o3 = {c:3}; var obj = Object.assign({}, o1, o2, o3); "
+                 "Object.values(obj);"),
+      njs_str("1,2,3") },
+
+    { njs_str("var v1 = 'abc'; var v2 = true; var v3 = 10; "
+                 "var obj = Object.assign({}, v1, null, v2, undefined, v3); "
+                 "Object.values(obj);"),
+      njs_str("a,b,c") },
+
+    { njs_str("Object.assign(true, {a:123})"),
+      njs_str("true") },
+
+    { njs_str("Object.assign(true, {a:123}).a"),
+      njs_str("123") },
+
+    { njs_str("var y = Object.create({s:123}); y.z = 456;"
+                 "Object.assign({}, y).s;"),
+      njs_str("undefined") },
+
+    { njs_str("var obj = {s:123}; Object.defineProperty(obj,"
+                 "'p1', {value:12, enumerable:false});"
+                 "Object.assign({}, obj).p1"),
+      njs_str("undefined") },
+
+    { njs_str("var obj = {s:123}; Object.defineProperty(obj,"
+                 "'x', {value:12, writable:false});"
+                 "Object.assign(obj, {x:4})"),
+      njs_str("TypeError: Cannot assign to read-only property \"x\" of object") },
+
+    { njs_str("var obj = {foo:1, get bar() {return 2;}};"
+                 "var copy = Object.assign({}, obj);"
+                 "Object.getOwnPropertyDescriptor(copy, 'bar').get"),
+      njs_str("undefined") },
+
+    { njs_str("try{var x = Object.defineProperty({}, 'foo',"
+                 "{value:1, writable:false});"
+                 "Object.assign(x, {bar:2}, {foo:2});}catch(error){};"
+                 "x.bar"),
+      njs_str("2") },
+
+    { njs_str("var a = Object.defineProperty({}, 'a',"
+                 "{get(){Object.defineProperty(this, 'b',"
+                 "{value:2,enumerable:false});"
+                 "return 1}, enumerable:1}); a.b =1;"
+                 "var x = Object.assign({}, a);x.b;"),
+      njs_str("undefined") },
 };