JS基础必知必会

137 阅读3分钟

一、JS数据类型有哪些

ES6之前 基本的:数字number、字符串string、布尔值boolean
表示空/无的:nullundefined
表示对象:object
ES6后新加的: symbolbigInt

二、原型链是什么

1. 概念

假设我们有一个普通对象obj={},这个obj会有一个隐藏属性,叫__proto__,这个属性会指向Object.prototype,即

obj.__proto__ = Object.prototype

此时,我们说obj的原型是Object.prototype,或者说Object.prototypeobj的原型。而这个隐藏属性的作用就是用来指向对象的原型的。

假设我们有一个数组对象arr=[],这个arr也会有一个隐藏属性,这个隐藏属性会指向Array.prototype,即

arr.__proto__ = Array.prototype

同时,这个Array.prototype也有一个隐藏属性,指向了Object.prototype,即

Array.prototype.__proto__ = Object.prototype

这样一来,arr就有两层原型,通过隐藏属性形成原型链。

2. 实现方法

普通做法:

a = {}, b = {}
a.__proto__ = b
b.__proto__ = Object.prototype

推荐做法:

a = Object.create({}) // ES6
a = new 构造器() // ES5
a.__proto__ = 构造器名.prototype

3. 解决问题

在ES6之前,没有class的情况下实现继承。以刚刚的arr.__proto__ ==> Array.prototype ==> Object.prototype为例,我们说:

  • arrArray的实例,arr拥有Array.prototype的属性
  • Array继承了Object
  • 所以arrObject的间接实例,也拥有Object.prototype里的属性 这样一来,arr就拥有Array.prototypeObject.prototype的属性

4. 优缺点

优点:简单、优雅 缺点:跟class相比,不支持私有属性

5. 解决缺点

使用ES6的class (在属性前加#来声明私有属性)

三、this是什么

var length = 1;
function callback(){
    console.log(this.length)
}

const obj = {
    length: 2,
    myMethod(callback){
        callback()
    }
}

obj.myMethod(callback); // 1

四、new是什么

  1. 创建临时对象
  2. 绑定原型(共有属性)
  3. 指定this = 临时对象 (this.__proto__ = 构造函数.prototype)
  4. 执行构造函数 (自有属性)
  5. 返回临时对象

五、立即执行函数是什么

  1. 概念:声明一个函数并立即执行。
  2. 实现方法:
( function(){console.log('我是立即执行函数')}() ) //用括号把整个表达式包起来
( function(){console.log('我是立即执行函数')} )() //用括号把整个函数包起来
  1. 解决问题:在ES6之前创建局部作用域
  2. 优点:兼容性好(ES3都可以使用)
  3. 缺点:语法比较丑
  4. 解决缺点:使用ES6的块+let的语法

六、闭包是什么

  1. 概念:闭包是JS的一种语法特性(有很多语言也支持闭包),是一个能够存取包含作用域的函数
  2. 实现方法:
{
    let count = 0; // 不能是全局变量,不能是局部变量。要是自由变量
    function add(){
        count += 1;
    }
}

const add = function() {
    var count = 0;
    return () => { count += 1}
} ()
  1. 解决问题:一、避免污染全局环境(使用局部变量)。二、提供对局部变量的间接访问。三、维持变量,使其不被垃圾回收。
  2. 优点:简单、好用
  3. 缺点:闭包使用不当可能造成内存泄露。IE浏览器以前有个bug,
function test(){
    let x = 1;
    let y = 2;
    return () => { console.log(x) }
}

const myFn = test();
const myX = myFn();

对于一个正常的浏览器来说,y会在一段时间后自动消失(被垃圾回收器回收掉)。但是旧版本IE并不会。 6. 解决缺点:少用,慎用

七、JS如何实现类

方法一、使用原型

function Dog(name,kind){
    this.name = name;
    this.kind = kind;
    this.legsNumber = 4;
}

Dog.prototype = {
    constructor: Dog, // 注意:这种写法要加上构造器属性
    species: 'dog',
    bark: () => { console.log('bark!'); }
}

方法二、使用class

class Dog{
    static species = 'dog';
    legsNumber = 4; // 等价于在constructor里写this.legsNumber = 4
    constructor(name, kind){
        this.name = name;
        this.kind = kind;
    }
    bark() {
        console.log('bark!');
    }
}

八、JS如何实现继承

方法一、使用原型

function Animal(legsNumber){
    this.legsNumber = legsNumber;
}


function Dog(name,kind){
    Animal.call(this, 4);
    this.name = name;
    this.kind = kind;
}

Dog.prototype = new Animal();
// 假如不想要Animal返回的对象上的legsNumber属性到prototype上,可以使用以下方式
const EmptyAnimal = function(){};
EmptyAnimal.prototype = Animal.prototype;
Dog.prototype = new EmptyAnimal();

Dog.prototype.species = 'dog';
Dog.prototype.bark = () => { console.log('bark!'); };

方法二、使用class

class Animal{
    constructor(legsNumber){
        this.legsNumber = legsNumber;
    }
}

class Dog extends Animal{
    static species = 'dog';
    constructor(name, kind){
        super(4); // 必须先于其他语句执行
        this.name = name;
        this.kind = kind;
    }
    bark() {
        console.log('bark!');
    }
}