前端面试——JS基础

变量类型和计算

1. 值类型与引用类型

值类型:字符串string,数值number,布尔值boolean, null,undefined,symbol
引用类型:对象 Object,数组Array,函数Function

考点

  1. 存储方式,值类型的数据是存储在栈中,引用类型的数据存储在堆中,栈中存储的是在数据在堆中的地址。
  2. 引用类型的赋值,赋值的是变量的存储地址,修改其中一个变量的属性时,会对另一个变量造成影响。(这就是浅拷贝)
var person = { name: 'Mary', sex: 21 };
var person1 = person;
person1.name = 'Json';
console.log(JSON.stringify(person1));  // {"name": "Json", "sex":"21"}

2. typeof 类型判断

typeof 能判断出除null以外的所有值类型,typeof(null)的值为'object',判断数组与函数的值也为'object'。

3. 深拷贝与浅拷贝

浅拷贝:B复制了A,修改A时,B跟着变化。

let a=[0,1,2,3,4],
b=a;
console.log(a===b);//true
a[0]=1;
console.log(a,b)//[1,1,2,3,4]

深拷贝:复制之后是两个独立个体,互不影响。

实现深拷贝的方式

  1. 使用JSON.parse(JSON.stringify())
var obj1 = {
    a: 1,
    b: 2,
    c: 3
}
var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.a = 4;
console.log(obj1.a);  // 1
console.log(obj2.a); // 4
  1. 递归
/**
 * 深拷贝
 */

const obj1 = {
    age: 20,
    name: 'xxx',
    address: {
        city: 'beijing'
    },
    arr: ['a', 'b', 'c']
}
const obj2 = deepClone(obj1)
obj2.address.city = 'shanghai'
obj2.arr[0] = 'a1'
console.log(obj1.address.city)//beijing
console.log(obj1.arr[0])//a

/**
 * 深拷贝
 * @param {Object} obj 要拷贝的对象
 */
function deepClone(obj = {}) {
    if (typeof obj !== 'object' || obj == null) {
        // obj 是 null ,或者不是对象和数组,直接返回
        return obj
    }
    // 初始化返回结果
    let result
    if (obj instanceof Array) {
        result = []
    } else {
        result = {}
    }
    for (let key in obj) {
        // 保证 key 不是原型的属性
        if (obj.hasOwnProperty(key)) {
            // 递归调用
            result[key] = deepClone(obj[key])
        }
    }
    // 返回结果
    return result
}
  1. Object.assign(target,testArr)
    仅限于单层的引用类型进行深拷贝。
 var obj1 = {
    a: 1,
    b: 2,
    c: 3
}
var obj2 = Object.assign({}, obj1);
obj2.b = 4;
console.log(obj1.b); // 2
console.log(obj2.b); // 4
var obj1 = {
   a: 1,
   b: 2,
   c: ['a','b','c']
}
var obj2 = Object.assign({}, obj1);
obj2.c[1] = 1;
console.log(obj1.c); // ["a", 1, "c"]
console.log(obj2.c); // ["a", 1, "c"]

变量计算

  1. 字符串拼接
var a=100+10
var b=100+'10'
console.log(a)  // 110
console.log(b)  //'10010'
  1. '==' 运算符
console.log(100=='100')  // true
console.log(''==0)  // true
console.log(null==undefined)  // true

原型与原型链

1. class和继承

js本身没有类的概念,继承是通过原型链来实现的
js继承的本质就是子类共享父类的原型对象

// 类
class Student {
    constructor(name, number) {
        this.name = name
        this.number = number
        // this.gender = 'male'
    }
    sayHi() {
        console.log(
            `姓名 ${this.name} ,学号 ${this.number}`
        )
    }
}
// 通过类 new 对象/实例
const xialuo = new Student('夏洛', 100)
console.log(xialuo.name)
console.log(xialuo.number)
xialuo.sayHi()
const madongmei = new Student('马冬梅', 101)
console.log(madongmei.name)
console.log(madongmei.number)
madongmei.sayHi()
// 父类
class People {
    constructor(name) {
        this.name = name
    }
    eat() {
        console.log(`${this.name} eat something`)
    }
}

// 子类
class Student extends People {
    constructor(name, number) {
        super(name)
        this.number = number
    }
    sayHi() {
        console.log(`姓名 ${this.name} 学号 ${this.number}`)
    }
}

// 子类
class Teacher extends People {
    constructor(name, major) {
        super(name)
        this.major = major
    }
    teach() {
        console.log(`${this.name} 教授 ${this.major}`)
    }
}
// 实例
const xialuo = new Student('夏洛', 100)
console.log(xialuo.name)
console.log(xialuo.number)
xialuo.sayHi()
xialuo.eat()
// 实例
const wanglaoshi = new Teacher('王老师', '语文')
console.log(wanglaoshi.name)
console.log(wanglaoshi.major)
wanglaoshi.teach()
wanglaoshi.eat()
2. 原型与原型链

隐式原型:

console.log(xialuo.__proto__)

显式原型:

console.log(Student.prototype)
console.log(xialuo.__proto__===Student.prototype)//true
原型.png
  • 每个class都有显式原型prototype。
  • 每个实例都有隐式原型proto
  • 实例的proto指向对应class的prototype。
    实例获取属性或方法时,先在自身中寻找,如果没有找到就到隐式原型中寻找

原型链

原型链.png

instanceof
判断实例是否在原型链中。

console.log(xialuo instanceof People)//true

闭包

闭包是指有权访问另外一个函数作用域中的变量的函数。可以理解为(能够读取其他函数内部变量的函数) 。
闭包的作用: 正常函数执行完毕后,里面声明的变量被垃圾回收处理掉,但是闭包可以让作用域里的变量,在函数执行完之后依旧保持没有被垃圾回收处理掉。

// 函数作为返回值
// function create() {
//     const a = 100
//     return function () {
//         console.log(a)
//     }
// }
// const fn = create()
// const a = 200
// fn() // 100
// 函数作为参数被传递
function print(fn) {
    const a = 200
    fn()
}
const a = 100
function fn() {
    console.log(a)
}
print(fn) // 100

异步和单线程

单线程

js是单线程语言,只能同时做一件事。

console.log(100); 
setTimeout(function(){
    console.log(300)
},2000);
console.log(400)
console.log(100)
alert(200)
console.log(300)
异步的使用场景
  • 网络请求,如ajax图片加载
  • 定时任务,如setTimeout
promise的使用

es6之前使用回调函数来实现异步,有时候会陷入“回调地狱”,例如ajax嵌套,需要用第一层取到的数据去调第二层,依次类推。
promise实现异步加载图片:

function loadImg(src) {
    const p = new Promise(
        (resolve, reject) => {
            const img = document.createElement('img')
            img.onload = () => {
                resolve(img)
            }
            img.onerror = () => {
                const err = new Error(`图片加载失败 ${src}`)
                reject(err)
            }
            img.src = src
        }
    )
    return p
}

// const url = 'https://img.baidu.com/5a9fc8070001a82402060220-140-140.jpg'
// loadImg(url).then(img => {
//     console.log(img.width)
//     return img
// }).then(img => {
//     console.log(img.height)
// }).catch(ex => console.error(ex))

const url1 = 'https://img.baidu.com/93nsun2sa-img.-140.jpg'
const url2 = 'https://img3.b.com/5a9udiafc8070001a82402060220-100-100.jpg'

loadImg(url1).then(img1 => {
    console.log(img1.width)
    return img1 // 普通对象
}).then(img1 => {
    console.log(img1.height)
    return loadImg(url2) // promise 实例
}).then(img2 => {
    console.log(img2.width)
    return img2
}).then(img2 => {
    console.log(img2.height)
}).catch(ex => console.error(ex))

你可能感兴趣的:(前端面试——JS基础)