中性子コンポーネントVUEのVUEは、中性子コンポーネントの小道具に誘起された変更を修正誘発小道具のjsの深いコピーと浅いコピーでの反射のjsの深いコピーと浅いコピーでの反射

修正小道具VUE中性子コンポーネントのJS深いコピーと浅いコピー上の反射が原因

 

小道具によって達成される反応またはVUE、親コンポーネントとサブアセンブリ通信のいずれかで、親コンポーネントのVUEに小道具は、公式の言葉を一方向のデータフローは、次の更新の親小道具これは、サブアセンブリに流下するが、その逆はありません。言い換えれば、子どもたちは小道具を修正することはできません。しかし、実際の開発プロセスは、場合によってはデータの小道具を変更しようとするがあるかもしれません。

ローカル変数が使用されているように1、唯一の小道具は、初期値を渡し、そのサブアセンブリ、これは一般的に、それに割り当てられた値は、小道具、ローカルデータプロパティを定義しています。次のように:

1
2
3
4
5
6
props: [ 'initialCounter' ],
data: function () {
   return  {
     counter:  this .initialCounter
   }
}

図2は、入ってくる生データに小道具の値が、そのサブコンポーネントを変換する必要があります。この場合には、次のように計算された属性を定義する計算を使用することが好ましいです。

小道具:[ 'サイズ']、
計算:{ 
  normalizedSize:関数(){ 
    戻りthis.size.trim()toLowerCaseメソッド()
  } 
}

どちらの場合も、基本データ型の値が渡されますが、ほとんどの場合には、我々はサブコンポーネントへの参照型のデータを渡す必要があり、その後、問題が来ました。

アレイまたはオブジェクトタイプのために、それを支えるサブアセンブリ状態の親コンポーネントに影響を与える対象またはアレイ自体を変更するようにするJavaScriptのオブジェクトと配列は、参照によって渡されます。

例えば、親コンポーネントの一覧、ダブルクリックして編集要素があり、データがサブアセンブリとしての要素小道具、サブアセンブリ内のデータを編集する必要に伝達され、親を編集した後、前述したように、あなたは見つけるでしょう部品の値も変更されています。実際に、私たちは親コンポーネントのサブアセンブリに影響を与えるようにしたい、サブアセンブリは、変更が、親コンポーネントに影響を与えません。VUE公式のラインは、一見、この状況がどのように処理すべきかを説明していませんでした。

ここでの状況は、比較的単純なポイントであり、小道具をObject.assign送信する際に使用されるデータのコピーが(このデータは、単一レベルのオブジェクトである)、次いで、サブアセンブリ内部編集します。Object.assignは、合併の目的を達成するために、それは、おなじみのオブジェクトはオブジェクトではないことができますされている場合には、浅いコピーです。

再び次のJSディープコピーと、関連知識の浅いコピーに統合するために、関連する情報へのアクセスはそう。

図1に示すように、基本データ型と格納位置の参照データ

 基本データ型は、スタックメモリに記憶されている、そのようなVARをA = 1。

コピー動作Bは=ときに、次のように、メモリ内のスタックメモリを開きます。

補完的なメモリの変数a、bの影響は、bの値は、この時点で変更された場合の値には影響を与えません。

ヒープメモリに格納されたデータの参照型、参照型名は、スタックメモリに格納された値は、ヒープメモリであり、メモリスタックが、アドレスヒープメモリに格納された値に基準点を提供するされます。

Bは、コピー操作を=とき、アドレス参照がなく、メモリヒープの値よりも、コピーされます。

我々は場合[0] = 1の配列を変更するときに点AとBが同じアドレスであるので、当然、浅いコピーと呼ばれるBの影響を受けているので、。

実際には、我々は次のようになります。効果を希望しました:

さて、ここで、最後にコピーの深さは何ですか。

換言すれば、参照のみコピー(アドレス)のために、コピーした後、元の変数と同じものを新しい変数ポインティングとして互いに互いに影響との間の動作  浅いコピー

それは別のアドレスと、ヒープ内の再割り当てメモリであり、その値が同じで、コピーした後、元のオブジェクトのオブジェクトが完全に絶縁され、互いに独立して、ある場合に  ディープコピー

 

達成されたコピーその検討中のJS方法:

针对数组有这些方法:

Array.slice()

1
2
var  a=[1,2,3];
var  b=a.slice();<br>b[0]=4;<br>console.log(b); //[4,2,3]<br>console.log(a);//[1,2,3]

Array.concat

1
2
3
4
5
var  a=[1,2,3];
var  b=a.concat();
b[0]=4;
console.log(b); //[4,2,3]
console.log(a); //[1,2,3]

 当然,也可以遍历数组赋值。

但是以上两种只对单级结构的数组有效,如果数组的元素是一个引用类型,就不行了,比如:

1
2
3
4
5
let  a=[0,1,[2,3],4],
         b=a.slice();
a[0]=1;
a[2][0]=1;
console.log(a,b);

 

修改二维数组的元素还是会影响原数组,也就是说slice和concat实际上是浅拷贝。

针对对象:

Object.assign()

1
2
3
4
5
6
7
var  a={
   "name" : "张三" 
};
b=Object.assign({},a);
b.name= "李四"
console.log(b.name); //李四
console.log(a.name); //张三

同样该方法也是浅拷贝,如果对象属性值是引用类型也不行;

那么到底有哪些办法可以实现深拷贝呢

1、递归

复制代码
function deepClone(obj){
    let objClone = Array.isArray(obj)?[]:{};
    if(obj && typeof obj==="object"){
        for(key in obj){
            if(obj.hasOwnProperty(key)){
                //判断ojb子元素是否为对象,如果是,递归复制
                if(obj[key]&&typeof obj[key] ==="object"){
                    objClone[key] = deepClone(obj[key]);
                }else{
                    //如果不是,简单复制
                    objClone[key] = obj[key];
                }
            }
        }
    }
    return objClone;
}    
let a=[1,2,3,4],
    b=deepClone(a);
a[0]=2;
console.log(a,b);
复制代码

2、jquery中的$.extend();

复制代码
var obj = {name:'xixi',age:20,company : { name : '腾讯', address : '深圳'} };
var obj_extend = $.extend(true,{}, obj); //extend方法,第一个参数为true,为深拷贝,为false,或者没有为浅拷贝。
console.log(obj === obj_extend);
obj.company.name = "ali";
obj.name = "hei";
console.log(obj);
console.log(obj_extend);
复制代码

3、JSON对象的JSON.parse()和JSON.stringify();

复制代码
var obj = {name:'xixi',age:20,company : { name : '腾讯', address : '深圳'} };
var obj_json = JSON.parse(JSON.stringify(obj));
console.log(obj === obj_json);
obj.company.name = "ali";
obj.name = "hei";
console.log(obj);
console.log(obj_json);
复制代码

4、Lodash中的_.cloneDeep()

var objects = [{ 'a': 1 }, { 'b': 2 }];
 
var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// => false

 

虽然通过拷贝props数据解决了问题,但是拷贝后修改新数据的属性并不会触发vue的更新机制,需要强制更新$forceUpdate(),总觉得很奇怪,不知道大家有什么更好的办法没有,欢迎大家留言讨论。

 

参考文章:

https://zhuanlan.zhihu.com/p/26282765

https://zhuanlan.zhihu.com/p/26282765

不管是react还是vue,父级组件与子组件的通信都是通过props来实现的,在vue中父组件的props遵循的是单向数据流,用官方的话说就是,父级的props的更新会向下流动到子组件中,反之则不行。也就是说,子组件不应该去修改props。但实际开发过程中,可能会有一些情况试图去修改props数据:

1、这个props只是传递一个初始值,子组件把它当做一个局部变量来使用,这种情况一般定义一个本地的data属性,将props的值赋值给它。如下:

1
2
3
4
5
6
props: [ 'initialCounter' ],
data: function () {
   return  {
     counter:  this .initialCounter
   }
}

2、这个props的值以原始数据传入,但是子组件对其需要转换。这种情况,最好使用computed来定义一个计算属性,如下:

props: ['size'],
computed: {
  normalizedSize: function () {
    return this.size.trim().toLowerCase()
  }
}

以上两种情况,传递的值都是基本数据类型,但是大多数情况下,我们需要向子组件传递一个引用类型数据,那么问题就来了。

JavaScript 中对象和数组是通过引用传入的,所以对于一个数组或对象类型的 prop 来说,在子组件中改变这个对象或数组本身将会影响到父组件的状态。

比如,在父组件中有一个列表,双击其中一个元素进行编辑,该元素的数据作为props传递给一个子组件,在子组件中需要对该数据进行编辑,你会发现如上所说,编辑后父组件的值也发生了变化。实际上我们想父组件影响子组件,但是子组件修改不要影响父组件。vue官网上貌似没说明这种情况应该如何处理。

这里情况相对简单点,在传递props时用Object.assign拷贝一份数据(这里数据是一个单层级对象),然后在子组件里面对其进行编辑。Object.assign能实现对象的合并,但是它是浅拷贝,也就是说如果对象的熟悉也是对象就不行。

于是查阅了相关资料,再次巩固下JS中深拷贝与浅拷贝的相关知识。

1、基本数据类型和引用数据类型的存储位置

 基本数据类型是存储在栈内存中,比如 var a=1;

当进行复制操作b=a时,会在栈内存中再开一个内存,如下

变量a和变量b的存储互补影响,如果此时修改b的值不会影响a的值。

引用类型数据存储在堆内存中,引用类型的名是存储在栈内存中,值是存储在堆内存中,但是栈内存会提供引用地址指向堆内存中的值。

当进行b=a的复制操作时,复制的是引用地址,而不是堆内存中的值。

而当我们a[0]=1时进行数组修改时,由于a与b指向的是同一个地址,所以自然b也受了影响,这就是所谓的浅拷贝了。

而实际上我们希望的效果应该是这样:

好,到这里,到底什么是深浅拷贝:

对于仅仅是复制了引用(地址),换句话说,复制了之后,原来的变量和新的变量指向同一个东西,彼此之间的操作会互相影响,为 浅拷贝

而如果是在堆中重新分配内存,拥有不同的地址,但是值是一样的,复制后的对象与原来的对象是完全隔离,互不影响,为 深拷贝

 

回顾下JS里实现拷贝的方法有哪些:

针对数组有这些方法:

Array.slice()

1
2
var  a=[1,2,3];
var  b=a.slice();<br>b[0]=4;<br>console.log(b); //[4,2,3]<br>console.log(a);//[1,2,3]

Array.concat

1
2
3
4
5
var  a=[1,2,3];
var  b=a.concat();
b[0]=4;
console.log(b); //[4,2,3]
console.log(a); //[1,2,3]

 当然,也可以遍历数组赋值。

但是以上两种只对单级结构的数组有效,如果数组的元素是一个引用类型,就不行了,比如:

1
2
3
4
5
let  a=[0,1,[2,3],4],
         b=a.slice();
a[0]=1;
a[2][0]=1;
console.log(a,b);

 

修改二维数组的元素还是会影响原数组,也就是说slice和concat实际上是浅拷贝。

针对对象:

Object.assign()

1
2
3
4
5
6
7
var  a={
   "name" : "张三" 
};
b=Object.assign({},a);
b.name= "李四"
console.log(b.name); //李四
console.log(a.name); //张三

同样该方法也是浅拷贝,如果对象属性值是引用类型也不行;

那么到底有哪些办法可以实现深拷贝呢

1、递归

复制代码
function deepClone(obj){
    let objClone = Array.isArray(obj)?[]:{};
    if(obj && typeof obj==="object"){
        for(key in obj){
            if(obj.hasOwnProperty(key)){
                //判断ojb子元素是否为对象,如果是,递归复制
                if(obj[key]&&typeof obj[key] ==="object"){
                    objClone[key] = deepClone(obj[key]);
                }else{
                    //如果不是,简单复制
                    objClone[key] = obj[key];
                }
            }
        }
    }
    return objClone;
}    
let a=[1,2,3,4],
    b=deepClone(a);
a[0]=2;
console.log(a,b);
复制代码

2、jquery中的$.extend();

复制代码
var obj = {name:'xixi',age:20,company : { name : '腾讯', address : '深圳'} };
var obj_extend = $.extend(true,{}, obj); //extend方法,第一个参数为true,为深拷贝,为false,或者没有为浅拷贝。
console.log(obj === obj_extend);
obj.company.name = "ali";
obj.name = "hei";
console.log(obj);
console.log(obj_extend);
复制代码

3、JSON对象的JSON.parse()和JSON.stringify();

复制代码
var obj = {name:'xixi',age:20,company : { name : '腾讯', address : '深圳'} };
var obj_json = JSON.parse(JSON.stringify(obj));
console.log(obj === obj_json);
obj.company.name = "ali";
obj.name = "hei";
console.log(obj);
console.log(obj_json);
复制代码

4、Lodash中的_.cloneDeep()

var objects = [{ 'a': 1 }, { 'b': 2 }];
 
var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// => false

 

虽然通过拷贝props数据解决了问题,但是拷贝后修改新数据的属性并不会触发vue的更新机制,需要强制更新$forceUpdate(),总觉得很奇怪,不知道大家有什么更好的办法没有,欢迎大家留言讨论。

 

参考文章:

https://zhuanlan.zhihu.com/p/26282765

https://zhuanlan.zhihu.com/p/26282765

おすすめ

転載: www.cnblogs.com/mouseleo/p/11115174.html