JS基础笔记(一)

231 阅读4分钟

基础(一)


最近发现JS的基础原理其实还是蛮重要的,有些知识点没有深入了解,就会导致实际项目中的代码做了很多“无用功”。现在开始整理下最近回顾的一些基础的知识:


#### 提升 ##### 声明提升 ``` console.log(r); var r = 'hello world'; // 输出undefined ``` 上述代码等价于 ``` var r; console.log(r); r = 'hello world'; ``` 之所以会输出 undefined,原因就在于声明的提升,var 变量会提升到顶部进行声明。

再举个例子

var r = 'hello world';
var r;
console.log(r);

这段代码输出的会是 hello world 上述代码等价于

var r;
var r;
r = 'hello world';
console.log(r);
函数提升

如下例子 

console.log(a);
function a() {};
var a = 1;

输出将会是 f a() {}; 上述代码等价于

function a() {};
var a;
console.log(a);
a = 1;

函数会被提升,且优先于变量提升。

根据提升的例子,说明了var声明的变量会提升到作用域的顶部,且他会被挂在到window 上,这可能就会引发一些不可预估的问题。 下面看看 let 和 const

let a = 1;
var b = 1;
const c = 1;
console.log(window.a);
console.log(window.c);

function t() {
    console.log(b);
    let b;
}

t();

通过例子发现 a 和 c 都不会被挂载到window 上,而且使用let和const 的时候 如果前面已经声明过变量了,就不可以再次声明,否则会报错。

提升这个概念解决的问题其实是函数间的相互调用:

function test1() {
    test2();
}
function test2() {
    test1();
}   
test1();

如果不存在提升,上述代码执行不了


数组

map

生成一个新数组,遍历原数组,将每个元素拿出来做一些变换然后放入到新数组中。

[1, 2, 3].map(v => v + 1) // [2, 3, 4]

map回调函数接受三个参数,当前索引元素,索引,原数组

fliter

生成一个新数组,在遍历数组的时候将返回值作为true的元素放入新数组,删除一些不必要的元素

[1 , 2, 3].filter(item => item !== 2) // [1, 3]
reduce

将数组中的元素通过回调函数最终转换为一个值

数组元素累加

const a = [1, 2, 3, 4, 5];
const total = a.reduce((acc, currentValue) => acc + currentValue, 0);

reduce 接受两个参数分别是回调函数和初始值。

  • 上述代码首先将 0 作为初始值,会传入回调函数中的第一个参数。
  • 回调函数接受四个参数,分别是累计值,当前元素,当前索引,原数组。

通过reduce实现map

const a = [1, 2, 3];
a.map(item => item + 1) // [2, 3, 4]
a.reduce((acc, item) => { acc.push(item + 1); return acc; }, [])
slice

不改变原数组 用于返回一个新的指定范围的数组 第一个参数为startIndex,第二个参数为endIndex(可选) 如果第一个参数为负值,从最后一个开始算,-1为倒数第一个 只有第一个参数: 会返回[arr[startIndex], ...] 两个参数都包含的时候: 会返回[arr[startIndex], ..., arr[endIndex - 1]]

const a = [1, 2, 3, 4];
console.log(a.slice(2, 4)) // [3, 4]
splice

splice() 方法向/从数组中添加/删除项目,然后返回被删除的项目。 该方法会改变原始数组 arr.splice(index, howmany, item1, ..., itemx) index为必须,整数,规定添加/删除item的位置 howmany 必须 要删除的数目 imte1, ..., itemX 可选 向数组添加的新项目 返回一个新数组


apply bind call

apply有两个参数:指向对象,[参数列表] call有两个参数:指向对象,参数列表 bind支持上述两种 但是会返回一个函数 不会马上执行

手写call、apply、bind call

Function.prototype.newCall = function(context) {
    if (typeof this !== 'function') {
        throw new TypeError('Error')
    }
    context = context || window;
    context.fn = this;
    const args = [...arguments].slice(1);
    const result = context.fn(...args);
    delete context.fn;
    return result;
}
  • 首先context为可选参数,如果不传入,默认windows
  • 判断当前是否为函数
  • 给context创建一个fn属性,将值设置为需要调用的函数
  • call可传入多个,剥离出来。
  • 调用函数后,将对向上的fn删除

apply

Function.prototype.newApply = function(context) {
    if (typeof this !== 'function'){
        throw new TypeError('Error');
    }
    context = context || window;
    context.fn = this;
    let result;
    if ([arguments][1]) {
        result = context.fn(...args)
    } else {
        retule = context.fn();
    }
    delete context.fn;
    return result;
}

new的原理是什么 new创建和字面量创建的区别

调用 new 的时候发生以上四件事情:

  • 新生成一个空对象
  • 链接到原型
  • 绑定this
  • 返回新的对象
function create() {
    let obj = {};
   
}

instanceof 的原理

function myInstanceof(left, right) {
    let prototype = right.prototype;
    left = left.__proto__;
    whilt(true) {
        if (prototype === left) {
            return true;
        }
        if(left === null || left === undefined)
            return false;
        left = left.__proto__;
    }
}
  • 首先获取类型的原型
  • 然后获取对象的原型
  • 然后一直循环判断对象的原型是否等于类型的原型,一直到原型对象为null

为什么0.1 + 0.2 !== 0.3

JS采用IEEE 754双精度版本