JS 浅拷贝——Shallow copy 在 Canvas 绘图中的应用

(一)简述 JavaScript 浅拷贝 和 深拷贝

在介绍浅拷贝和深拷贝的概念之前,我们不妨先了解一下 JavaScipt 变量的两种保存方式。

ECMAScript 变量可能包含两种不同数据类型的值:基本类型值引用类型值。基本类型值指的是简单的数据段,而引用类型值指那些可能由多个值构成的对象。在将一个值赋给变量时,解析器必须确定这个值是基本类型值还是引用类型值。5 种基本数据类型:Undefined、Null、Boolean、Number 和 String。这 5 种基本数据类型是按值访问的,因为可以操作保存在变量中的实际的值。引用类型的值是保存在内存中的对象。与其他语言不同,JavaScript 不允许直接访问内存中的位置,也就是说不能直接操作对象的内存空间。在操作对象时,实际上是在操作对象的引用而不是实际的对象。为此,引用类型的值是按引用访问的

1.1 浅拷贝 Shallow copy

  • 对于基本类型的值,进行浅拷贝时,将一个变量复制给另一个变量,相当于创建了一个新值,两个变量是独立的,不会互相影响。举个栗子:
var a = 2;
var b = a;
a = 5;
console.log(a); //5
console.log(b); //2
  • 对于引用类型值,进行浅拷贝时,实际上只是将操作的对象的引用复制给另一个变量,两个变量指向同一个内存中的变量,修改其中任意一个变量将影响另一个变量,思考下面的例子:
var obj1 = new Object({'name' : 'John', 'age' : 19});
var obj2 = obj1;
obj1.name = 'Sara';
console.log(obj1); //{'name' : 'Sara', 'age' : 19}
console.log(obj2); //{'name' : 'Sara', 'age' : 19}

obj2.age = 30;
console.log(obj1); //{'name' : 'Sara', 'age' : 30}
console.log(obj2); //{'name' : 'Sara', 'age' : 30}

上面例子中,无论修改任何一个变量,都会直接修改这两个变量共同指向的内存中的对象,因此,两个变量的值同时改变。

(二)浅拷贝在Canvas绘图中的应用

我们使用Canvas绘图时,经常会遇到改变所绘图形的属性问题,比如控制位置的坐标点。使用浅拷贝,可以有效地节省代码,减少遍历次数,提高代码执行效率。

下面的例子将重点展示:浅拷贝在拖拽图形时如何改变图形的坐标属性。

 如上图所示,图中有三个多边形,我们移动其中一个红色的多边形,改变了红色多边形的坐标属性。

其中的逻辑是:当鼠标点击canvas画布时,判断鼠标是否落在多边形范围内,如果是,则找出这个多边形;并且将这个多边形对象浅拷贝给一个变量dragging;当鼠标移动时,实时改变dragging变量中的x,y属性,此时多边形对象的属性x, y也同时改变。

我们观察其中一个代码片段,思考其中应用的浅拷贝的原理:

下面代码节选自《Core HTML5 Canvas Graphics, Animation, and Game Development》。

// Event handlers.....................................................

//鼠标点击画布时...
canvas.onmousedown = function (e) {
   var loc = windowToCanvas(e.clientX, e.clientY); //获取当前鼠标位置

   e.preventDefault(); // prevent cursor change

   if (editing) { //进入编辑模式...
     polygons.forEach( function (polygon) { //遍历所有的多边形对象组成的数组polygons
        polygon.createPath(context); //绘制路径,但不描边
        if (context.isPointInPath(loc.x, loc.y)) { //判断鼠标位置是否落在多边形范围内
           saveDrawingSurface(); //储存画布信息
           mousedown.x = loc.x;  //储存鼠标信息
           mousedown.y = loc.y;

           dragging = polygon; //将当前选中的多边形对象浅拷贝给dragging
           draggingOffsetX = loc.x - polygon.x; //储存鼠标距离多边形中心点的偏移值
           draggingOffsetY = loc.y - polygon.y;
           return;
        }
     });
   }
   else { //进入绘图模式...
     startDragging(loc);
     dragging = true;
   }
};

//鼠标移动时......
canvas.onmousemove = function (e) {
   var loc = windowToCanvas(e.clientX, e.clientY);

   e.preventDefault(); // prevent selections

   if (editing && dragging) { //进行编辑模式并选中多边形
      dragging.x = loc.x - draggingOffsetX; //修改dragging.x值,直接修改了选中多边形的x属性
      dragging.y = loc.y - draggingOffsetY; //修改dragging.y值,直接修改了选中多边形的y属性

      context.clearRect(0, 0, canvas.width, canvas.height); //清除画布
      drawGrid('lightgray', 10, 10); //绘制网格线
      drawPolygons(); // 重新绘制所有的多边形
   }
   else { //略过......
     if (dragging) {
        restoreDrawingSurface();
        updateRubberband(loc, sides, startAngle);

        if (guidewires) {
           drawGuidewires(mousedown.x, mousedown.y);
        }
     }
   }
};

将选中的多边形对象复制给dragging变量,当修改dragging变量时,同时也改变了选中多边形的属性,节省了代码,避免了多次遍历数组,提高代码执行的效率。

 完整示例请查阅Github源码:https://github.com/corehtml5canvas/code/tree/master/ch02/example-2.28

 

 

 

 

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 黑客帝国 设计师:白松林 返回首页