02javaScript面试必备基础知识

值类型和引用类型的区别

值类型存值,引用类型存地址
常见值类型
	let a //undefined
	const s='abc'
	const n=100
	const b=true
	const s=Symbol('s')
常见引用类型
	const obj={ }
	const arr=[ ]
	const n=null  //特殊引用类型,指针指向为空地址
	//函数 特殊引用类型,不用于存储数据,所有没有“拷贝,复制函数”这一说
  //值类型
    let a = 100;
    let b = a;
    a = 200;
    console.log(b);//100
 //引用类型
    let a = { age: 10 };
    let b = a;
    a.age = 20;
    console.log(b.age)//20
  	
  	const obj1={x:100,y:200}
  	const obj2=obj1
  	let x1=obj1.x
  	obj2.x=101
  	x1=102
  	console.log(obj1) //{ x: 101, y: 200 }

typeof能判断哪些类型

识别所有值类型
识别函数
判断是否是引用类型Object(不可再细分)
 //判断所有值类型
    console.log(typeof a);//undefined
    console.log(typeof (str = 'abc'));//string
    console.log(typeof (n = 100));//number
    console.log(typeof (b = true));//boolean
    s = Symbol('S')
    console.log(typeof s);//symbol

    //判断函数
    console.log(typeof console.log) //function
    console.log(typeof function () { })//function

    //能识别引用类型
    console.log(typeof null);//object
    console.log(typeof ['a', 'b']);//object
    console.log(typeof { x: 20 });//object

手写深拷贝

/* 深拷贝*/
const obj1 = {
    age: 20,
    name: 'xxx',
    address: {
        city: 'beijing',
        a: {
            c: {
                d: 10,
            }
        }
    },
    arr: ['a', 'b', 'c']
}

const obj2 = deepClone(obj1)
console.log(obj2);
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
}

变量计算 —类型转换

字符串拼接
const a=100+10 //110
const b=100+'10' //'10010'
const c=true+'10' //'true10'

何时使用=== 何时使用==

==运算符
	除了==null之外,其他一律用===
100=='100' //true
0==' '//true
0==false //true
false==' '//true
null==undefined //true
const obj={x:10}
if(obj.a==null){}
//相当于 if(obj.a===null||obj.a===undefined){}
if语句和逻辑运算
	truly变量: !!a===true
	falsely变量:!!a===false
除以下是falsely变量,其余都是truely变量
	0,NaN,‘ ’,null,undefined,false
if语句的逻辑判断根据truely变量和falsely变量走分支

class和继承

继承extends ;类型判断instanceof
// 父类
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()

//类型判断-instanceof
console.log("-----instanceof-----");
console.log(xialuo instanceof Student);
console.log(xialuo instanceof People);
console.log(xialuo instanceof Object);
console.log([] instanceof Array);

原型和原型链

原型关系
	每个class都有显式原型prototype
	每个实例都有隐式原型__proto__
	实例的__proto__指向对应class的prototype	
基于原型的执行规则
	获取属性xialuo.name或执行方法xialuo.sayHi( )时,先在自身属性和方法查找
	如果找不到,则自动去__proto__中查找
注意
	class是ES6语法规范,由ECMA委员会发布
	ECMA只规定语法规则,即我们代码的书写规范,不规定如何实现
//class实际上是函数
console.log(typeof People);//function
console.log(typeof Student);//function

//隐式原型和显式原型
console.log(xialuo.__proto__)  //Student {}
console.log(Student.prototype) //Student {}
console.log(xialuo.__proto__===Student.prototype) //true

console.log(Student.prototype.__proto__); //People{}
console.log(People.prototype);//People{}
console.log(People.prototype === Student.prototype.__proto__);//true

class的原型本质,怎么理解?

在这里插入图片描述

如何准确判断一个变量是不是数组?

a instanceof Array

手写一个简易的jQuery,考虑插件和扩展性

class jQuery {
    constructor(selector) {
        const result = document.querySelectorAll(selector)
        const length = result.length
        for (let i = 0; i < length; i++) {
            this[i] = result[i]
        }
        this.length = length
        this.selector = selector
    }
    get(index) {
        return this[index]
    }
    each(fn) {
        for (let i = 0; i < this.length; i++) {
            const elem = this[i]
            fn(elem)
        }
    }
    on(type, fn) {
        return this.each(elem => {
            elem.addEventListener(type, fn, false)
        })
    }
    // 扩展很多 DOM API
}

// 插件
jQuery.prototype.dialog = function (info) {
    alert(info)
}

// “造轮子”
class myJQuery extends jQuery {
    constructor(selector) {
        super(selector)
    }
    // 扩展自己的方法
    addClass(className) {

    }
    style(data) {
        
    }
}

// const $p = new jQuery('p')
// $p.get(1)
// $p.each((elem) => console.log(elem.nodeName))
// $p.on('click', () => alert('clicked'))

作用域和自由变量

作用域:变量的合法使用范围
	全局作用域
	函数作用域
	块级作用域(ES6新增) 
自由变量
	一个变量在当前作用域没有被定义,但被使用了
	向上级作用域,一层一层依次寻找,直至找到为止
	如果全局作用域都没找到,则报错xx is not defined

如图:fn3()内没有定义a,a1,a2却被使用,那么一级一级依次向上查找。

闭包

作用域应用的特殊情况,有两种表现:
	函数作为参数被传递
	函数作为返回值被返回
所有的自由变量的查找,是在函数定义的地方,向上级作用域查找,不是在执行的地方!!!

函数作为返回值

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

this

this的不同应用场景,如何取值?
	作为普通函数:返回window
	使用call apply bind:传入什么返回什么。call()、apply()、bind() 都是用来重定义 this 这个对象的!
	作为对象方法被调用:返回对象本身
	在class方法中调用:当前实例本身
	箭头函数
		箭头函数中this的取值取上级作用域的this
this取什么值,是在函数执行时确定的,不是函数定义时确定的

在这里插入图片描述

在这里插入图片描述

左边:这个函数的执行是setTimeout本身触发的执行,作为普通函数而不是对象方法被执行。
右边:箭头函数中this的永远取它上级作用域的this,自己本身不会决定this的值。
 
class方法中调用:

手写bind函数

call、apply、bind

第一个参数传入要绑定的this对象。

// 模拟 bind
Function.prototype.bind1 = function () {
    // 将参数拆解为数组
    const args = Array.prototype.slice.call(arguments)

    // 获取 this(数组第一项)
    const t = args.shift()

    // fn1.bind(...) 中的 fn1
    const self = this

    // 返回一个函数
    return function () {
        return self.apply(t, args)
    }
}

function fn1(a, b, c) {
    console.log('this', this)
    console.log(a, b, c)
    return 'this is fn1'
}

const fn2 = fn1.bind1({ x: 100 }, 10, 20, 30)
const res = fn2()
console.log(res)

实际开发中闭包的应用场景,举例说明

闭包应用场景
隐藏数据

// 闭包隐藏数据,只提供 API
function createCache() {
    const data = {} // 闭包中的数据,被隐藏,不被外界访问
    return {
        set: function (key, val) {
            data[key] = val
        },
        get: function (key) {
            return data[key]
        }
    }
}

const c = createCache()
c.set('a', 100)
console.log( c.get('a') )

 

创建10个a标签,点击的时候弹出来对应的序号

//创建10个a标签,点击的时候弹出来对应的序号 
//不论点哪个,弹出都是10 
let i, a
for (i = 0; i < 10; i++) {
    a = document.createElement('a')
    a.innerHTML = i + '<br>'
    a.addEventListener('click', function (e) {
        e.preventDefault()
        alert(i)
    })
    document.body.appendChild(a)
}
//改进 弹出0 1 2
let a
for (let i = 0; i < 10; i++) {
    a = document.createElement('a')
    a.innerHTML = i + '<br>'
    a.addEventListener('click', function (e) {
        e.preventDefault()
        alert(i)
    })
    document.body.appendChild(a)
}

全局作用域vs块级作用域
块级作用域:每次循环产生一个新的块级作用域。click不是立即执行的函数。
前者,i是全局变量,在click之前i就变成10了。
后者,i是块级作用域,每次循环产生新作用域,click之前变成对应 i 值。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值