js基础,也许是高频笔试面试哦

1,138 阅读3分钟

1.基本数据类型

  • 数字
  • 字符串
  • 布尔值
  • undefined
  • null
  • symbol

基本数据类型是按值访问的,对象是按引用访问的,对象存储在堆中,栈中有引用指向这块堆内存

2.数据类型的转换

js中的表达式或者运算符,左右两边的东西,运行的时候会做类型转换,转换成它期望的类型

  • 对象(数组)转数字:先调valueof,如果返回的不是原始数据类型,则调tostring(eg: [] == 0)
  • 对象(数组)转字符串:先调tostring,如果返回的不是原始数据类型,则调valueof(eg: {} == 'xxx')
  • undefined转数字是NaN
  • null转数字是0

特殊:

  • null == undefined -> false
  • NaN == NaN -> false
  • NaN(包括自己)、null(除了自己)、undefined(除了自己)跟任何东西都不相等
  • 有(+)一边是字符串,就认为是字符串拼接

3.typeof和instanceOf的区别


// 原始数据类型的判断,函数跟对象有特殊:typeof 如果是函数就返回函数,是对象就返回对象。不能判断具体点的
console.log(typeof [])//object
console.log(typeof new RegExp('/A/'));//object
console.log(typeof function () { });//function
console.log(typeof null);// object特殊的
console.log(typeof 1);// number
console.log(typeof 'ss');// string

// 能判断具体的但是不能判断自定义类型的
console.log(Object.prototype.toString.call(new RegExp('/A/')))//[object RegExp]
class A { }
const a = new A();
console.log(Object.prototype.toString.call(a))//[object Object]



// instanceof 就是通过__proto__能找到的,  缺点不能判断原始数据类型
console.log([] instanceof Object); //true    [].__proto__.__proto__ === Object.prototype  因为这个为true
console.log([] instanceof Array); //true  [].__proto__ === Array.prototype 因为这个为true
function instanceofMy(A, B) {
  B = B.prototype;
  A = A.__proto__;

  while (true) {
    if (A === null) {
      return false;
    }

    if (A === B) {
      return true;
    }

    A = A.__proto__;
  }
}

console.log('str' instanceof String); // false 缺点不能判断原始数据类型

//  instance默认调用‘str’类上的 Symbol.hasInstance方法。所以我们可以复写String的这个方法,来自己实现

// constructor 也有相应的应用场景

4.call跟apply原理 apply只是第二个参数是数组别的没有差别

    Function.prototype.call = function (context, ...args) {
      // 万一context传的基本数据类型,就转一下Object(context),因为我们要给它加方法嘛
      context = context ? Object(context) : window;
      // 为了构造'ctx'.this(),  contexts上有this的方法(此处this指的的fn1)
      context.fn = this;

      // es6 直接这样就行了
      const r = context.fn(...args);
      delete context.fn;

      return r;
    }

    let a = { name: 9 };
    function fn1(p1, p2) {
      console.log(this, p1, p2);
    }

    fn1.call(a, 'p1', 'p2') // 正常执行
    fn1.call.call.call(a, 'p1', 'p2') //报错
    // --->  a['fn1.call.call']('p1', 'p2') ->  'p1'[a]('p2') -> a是个对象,你当方法执行,自然就报错了,说fn不是一个方法

    const a1 = function () { console.log('a1执行了,this是:', this, arguments); }
    const a2 = function () { console.log('a2执行了,this是:', this, arguments) }

    a1.call(a2, 'p1', 'p2');
    a1.call.call.call(a2, 'p1', 'p2');
    // --->  a2['a1.call.call']('p1', 'p2') -> obj('p1').a2('p2')

    a1.call.call.call(a2);
    // --->  a2['a1.call.call']() -> 无参数就是window.a2()

5.await基础知识

async function demo() {
  let rs = await new Promise((resolve, reject) => { 
    setTimeout(() => resolve('abc'), 3000) 
  })
  console.log(rs)
}
demo().then((abc) => {
  console.log(abc)
})
  • demo执行完后,返回的是一个promise,如果async function demo里没写return,会自动给包装成return Promise.resolve()
  • async function demo里写了return 普通对象{name:123},那么会自动包装成Promise.resolve({name:123})
  • 当然如果本身返回的就是一个promise就不用包装了,直接then就能取到上个promise成功的时候往resolve里放的参数
  • rs = await new Promise(xxx), rs拿到的是resolve里传的东西即:abc

6.函数有坑

  • 主要区别函数的定义形式
声明式:
function fn1(){}
fn1在声明它的作用域内可见,且fn1能被修改,在变量提升的时候,声明跟定义都提升

表达式:
- (function a(){})()
- var fn =  function b() {}
- +function c(){}
在变量提升的时候,只提升声明
函数名 a b c只在那个函数内可见,且是常量不能被重新赋值
题目:
var foo = 1;
(function foo(){
  foo = 10;
  console.log(foo)
})();  答案:打印foo函数(非严格模式)严格模式直接报错了

var fn =  function test2() {};  
test2()
答案:打印test2没有定义

+function name(){
    console.log(123);
}();

name();
答案:打印name没有定义