array常见基础数组实现原理

push:在数组末尾添加一个或多个元素,并返回新的长度。

因为源码中有很多内部函数做了很多的校验,所以我会先写一个简易的核心逻辑理解一下

简易的核心逻辑:

function Push(x, ...elements) {
    const length = x.length;

    for (let i = 0; i < elements.length; i++) {
        x[length + i] = elements[i];
    }

    return x.length;
}

v8的源码https://github.com/v8/v8/blob/4.9-lkgr/src/js/array.js第540行,

function ObservedArrayPush() {
//是为响应式什么的做准备的
  var n = TO_LENGTH_OR_UINT32(this.length);
  var m = %_ArgumentsLength();

  try {
    ObserveBeginPerformSplice(this);
    for (var i = 0; i < m; i++) {
      this[i+n] = %_Arguments(i);
    }
    var new_length = n + m;
    this.length = new_length;
  } finally {
    ObserveEndPerformSplice(this);
    ObserveEnqueueSpliceRecord(this, n, [], m);
  }

  return new_length;
}


// Appends the arguments to the end of the array and returns the new
// length of the array. See ECMA-262, section 15.4.4.7.
function ArrayPush() {
  CHECK_OBJECT_COERCIBLE(this, "Array.prototype.push");

  if (%IsObserved(this))
    return ObservedArrayPush.apply(this, arguments);

  var array = TO_OBJECT(this);
  var n = TO_LENGTH_OR_UINT32(array.length);
  var m = %_ArgumentsLength();

  // It appears that there is no enforced, absolute limit on the number of
  // arguments, but it would surely blow the stack to use 2**30 or more.
  // To avoid integer overflow, do the comparison to the max safe integer
  // after subtracting 2**30 from both sides. (2**31 would seem like a
  // natural value, but it is negative in JS, and 2**32 is 1.)
  if (m > (1 << 30) || (n - (1 << 30)) + m > kMaxSafeInteger - (1 << 30)) {
    throw MakeTypeError(kPushPastSafeLength, m, n);
  }
//核心方法
  for (var i = 0; i < m; i++) {
    array[i+n] = %_Arguments(i);
  }

  var new_length = n + m;
  array.length = new_length;
  return new_length;
}

pop():移除并返回数组的最后一个元素。

简易的核心逻辑:

  function pop(array , n) {
      var n = array.length;
      n--;
      var value = array[n];
      delete array[n];
      array.length = n;
      return value;
    }

v8的源码https://github.com/v8/v8/blob/4.9-lkgr/src/js/array.js第497行

function ArrayPop() {
  CHECK_OBJECT_COERCIBLE(this, "Array.prototype.pop");

  var array = TO_OBJECT(this);
  var n = TO_LENGTH_OR_UINT32(array.length);
  if (n == 0) {
    array.length = n;
    return;
  }

  if (%IsObserved(array))
    return ObservedArrayPop.call(array, n);

  n--;
  var value = array[n];
  %DeleteProperty_Strict(array, n);
  array.length = n;
  return value;
}

shift:移除并返回数组的第一个元素。

简易的核心逻辑:

function shift() {
    if(this.length === 0) {
        return undefined;
    }

    var firstElement = this[0];

    for (var i = 0; i < this.length; i++) {
        this[i] = this[i + 1];
    }

    this.length--;

    return firstElement;
}

v8的源码https://github.com/v8/v8/blob/4.9-lkgr/src/js/array.js第684行

function ArrayShift() {
  CHECK_OBJECT_COERCIBLE(this, "Array.prototype.shift");

  var array = TO_OBJECT(this);
  var len = TO_LENGTH_OR_UINT32(array.length);

  if (len === 0) {
    array.length = 0;
    return;
  }

  if (%object_is_sealed(array)) throw MakeTypeError(kArrayFunctionsOnSealed);

  if (%IsObserved(array))
    return ObservedArrayShift.call(array, len);

  var first = array[0];

  if (UseSparseVariant(array, len, IS_ARRAY(array), len)) {
    SparseMove(array, 0, 1, len, 0);
  } else {
    SimpleMove(array, 0, 1, len, 0);
  }

  array.length = len - 1;

  return first;
}

unshift():向数组的开头添加一个或多个元素,并返回新的长度

简易的核心逻辑:

function unshift(x ,...arguments) {
    // 将类数组对象转换为数组
    var array = Array.prototype.slice.call(x);

    // 获取传入参数的个数
    var num_arguments = arguments.length;

    // 计算新数组的长度
    var new_length = array.length + num_arguments;

    // 将数组往后推
    for (var i = new_length - 1; i >= num_arguments; i--) {
        array[i] = array[i - num_arguments];
    }
    // 给数组第一个位置赋值
    for (var j = 0; j < num_arguments; j++) {
        array[j] = arguments[j];
    }

    // 更新数组的长度
    array.length = new_length;
}

v8的源码https://github.com/v8/v8/blob/4.9-lkgr/src/js/array.js第735行

function ArrayUnshift(arg1) {  // length == 1
  CHECK_OBJECT_COERCIBLE(this, "Array.prototype.unshift");

  if (%IsObserved(this))
    return ObservedArrayUnshift.apply(this, arguments);

  var array = TO_OBJECT(this);
  var len = TO_LENGTH_OR_UINT32(array.length);
  var num_arguments = %_ArgumentsLength();

  if (len > 0 && UseSparseVariant(array, len, IS_ARRAY(array), len) &&
      !%object_is_sealed(array)) {
    SparseMove(array, 0, 0, len, num_arguments);
  } else {
    SimpleMove(array, 0, 0, len, num_arguments);
  }

  for (var i = 0; i < num_arguments; i++) {
    array[i] = %_Arguments(i);
  }

  var new_length = len + num_arguments;
  array.length = new_length;
  return new_length;
}

在51单片机中,处理小数点数组通常涉及到浮点数运算,但这并不是51单片机原生支持的功能,因为51系列单片机(如8051、AVR等)大多是基于固定位宽的寄存器和算术逻辑单元设计,它们主要用于整数操作。 然而,如果你需要近似地处理小数,一种常见的做法是在程序中手动模拟,即通过定点数乘法和除法来逼近浮点计算。比如,你可以创建两个数组,一个存储小数部分(通常是二进制补码形式),另一个存储指数。这样,每个数组元素代表一部分数值,并通过特定算法(如乘法-右移或者除法+偏置)来组合成一个完整的“小数点”精度的值。 举个简单的例子: ```c typedef struct { int mantissa; // 小数部分,例如16位用于1位小数精度 char exponent; // 指数,可以是1位或更少,表示小数点向左移动的位数 } FixedPoint; FixedPoint decimal_array[] = { { 1, 0 }, { 2, 0 }, { 4, 0 } }; // 代表0.1, 0.2, 0.4 // 假设有个操作需要将0.1加到某个变量上,可以这样做: int sum; for (int i = 0; i < sizeof(decimal_array) / sizeof(FixedPoint); ++i) { sum += decimal_array[i].mantissa * pow(2, decimal_array[i].exponent); } ``` 请注意,这种方式效率较低,不适合精确的科学计算,但对于一些简单的嵌入式应用来说,已经足够使用。实际应用中,如果对性能有较高要求,你可能需要考虑使用专门针对微控制器的浮点硬件库,或者使用支持浮点运算的更高级别单片机。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值