即使相同的命令在其他地方工作,也尝试分配给只读属性?

Posted

技术标签:

【中文标题】即使相同的命令在其他地方工作,也尝试分配给只读属性?【英文标题】:Attempted to assign to readonly property even though same command works elsewhere? 【发布时间】:2016-08-08 00:53:47 【问题描述】:

我有一个 javascript 函数(在基于 Angular 2 NativeScript 的移动应用程序中),它在按下按钮时触发,它应该隐藏按钮并在其位置显示一个活动指示器,执行蓝牙扫描,完成后切换关闭活动指示器并显示原始按钮。

bluetoothAdd() 
    this.isScanning = true;
    var plusIcon = this.page.getViewById("add");
    plusIcon.style.opacity = 0;
    bluetooth.hasCoarseLocationPermission().then(
        function (granted) 
            if (!granted) 
                bluetooth.requestCoarseLocationPermission();
             else 
                bluetooth.startScanning(
                    serviceUUIDs: ["133d"],
                    seconds: 4,
                    onDiscovered: function (peripheral) 
                        console.log("Periperhal found with UUID: " + peripheral.UUID);
                    
                ).then(function () 
                    console.log("scanning complete");
                    this.isScanning = false;
                    plusIcon.style.opacity = 1;
                , function (err) 
                    console.log("error while scanning: " + err);
                );
                this.isScanning = false;
            
        );

不幸的是,this.isScanning = false; 行会引发所有这些错误。我做错了什么?

CONSOLE ERROR file:///app/tns_modules/angular2/src/platform/server/parse5_adapter.js:55:75: EXCEPTION: Error: Uncaught (in promise): TypeError: Attempted to assign to readonly property.
CONSOLE ERROR file:///app/tns_modules/angular2/src/platform/server/parse5_adapter.js:53:75: STACKTRACE:
CONSOLE ERROR file:///app/tns_modules/angular2/src/platform/server/parse5_adapter.js:53:75: resolvePromise@file:///app/tns_modules/zone.js/dist/zone-node.js:496:41
file:///app/tns_modules/zone.js/dist/zone-node.js:532:32
invokeTask@file:///app/tns_modules/zone.js/dist/zone-node.js:314:43
onInvokeTask@file:///app/tns_modules/angular2/src/core/zone/ng_zone_impl.js:35:51
invokeTask@file:///app/tns_modules/zone.js/dist/zone-node.js:313:55
runTask@file:///app/tns_modules/zone.js/dist/zone-node.js:214:58
drainMicroTaskQueue@file:///app/tns_modules/zone.js/dist/zone-node.js:432:43
promiseReactionJob@[native code]
UIApplicationMain@[native code]
start@file:///app/tns_modules/application/application.js:233:26
file:///app/tns_modules/nativescript-angular/application.js:65:26
ZoneAwarePromise@file:///app/tns_modules/zone.js/dist/zone-node.js:542:38
nativeScriptBootstrap@file:///app/tns_modules/nativescript-angular/application.js:64:23
anonymous@file:///app/main.js:5:36
evaluate@[native code]
moduleEvaluation@[native code]
[native code]
promiseReactionJob@[native code]
CONSOLE ERROR file:///app/tns_modules/zone.js/dist/zone-node.js:419:27: Unhandled Promise rejection: Attempted to assign to readonly property. ; Zone: angular ; Task: Promise.then ; Value: TypeError: Attempted to assign to readonly property.
CONSOLE ERROR file:///app/tns_modules/zone.js/dist/zone-node.js:421:23: Error: Uncaught (in promise): TypeError: Attempted to assign to readonly property.
CONSOLE LOG file:///app/Pages/Home/home.component.js:99:32: scanning complete

【问题讨论】:

【参考方案1】:

问题在于,一旦您进入 Promise,您将处于不同的上下文中; “this”不再指向您认为的“this”,因此您需要将“this”保存到另一个变量中;有些人使用“that”、“self”甚至“_this”...

所以这个问题的解决方案是;

bluetoothAdd() 
    this.isScanning = true;
    var plusIcon = this.page.getViewById("add");
    plusIcon.style.opacity = 0;

    var self = this; // THIS LINE ADDED

    bluetooth.hasCoarseLocationPermission().then(
        function (granted) 
            if (!granted) 
                bluetooth.requestCoarseLocationPermission();
             else 
                bluetooth.startScanning(
                    serviceUUIDs: ["133d"],
                    seconds: 4,
                    onDiscovered: function (peripheral) 
                        console.log("Periperhal found with UUID: " + peripheral.UUID);
                    
                ).then(function () 
                    console.log("scanning complete");
                    self.isScanning = false; // CHANGED!
                    plusIcon.style.opacity = 1;
                , function (err) 
                    console.log("error while scanning: " + err);
                );
                self.isScanning = false; // CHANGED!
            
        );


更新 ES6 方法 -- 你也可以使用 ES6 箭头函数=> 例如,您可以将第一行更改为:

   bluetooth.hasCoarseLocationPermission().then(
            (granted) => 

在这种情况下,因为您使用了 ES6 箭头函数,this 将自动来自父作用域;因此,您无需使用self_thisthat 技巧。

从 NativeScript 2.4 开始,iosandroid 都支持 ES6。

【讨论】:

以上是关于即使相同的命令在其他地方工作,也尝试分配给只读属性?的主要内容,如果未能解决你的问题,请参考以下文章

来自 apollo-boost 的 ApolloClient 试图分配给只读属性

无法分配给对象的只读属性“stopImmediatePropagation”

TypeError:无法分配给只读属性 - Karma

属性或索引器不能分配给“”它是只读的[重复]

无法使用 .map() 分配给只读属性。使用 NextJs 反冲

业力测试:TypeError:试图分配给只读属性