最全web前端面试高频考点——JavaScript 篇(一)【JS的三座大山

!!0 === false
!!NaN === false
!!'' === false
!!null === false
!!undefined == false
!!false === false

示例 4:逻辑判断


注:10 是 truly 变量,继续往后判断返回第二个值



console.log(10 && 0) // 0
console.log('' || 'abc') // 'abc'
console.log(!window.abc) // true

## 原型和原型链


### class 类


* constructor
* 属性
* 方法


示例:



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

// 通过类 new 对象/实例
const xialu = new Student('夏洛', '2022')
console.log(xialu.name) // 夏洛
console.log(xialu.number) // 2022
xialu.sayHi() // 姓名 夏洛, 学号 2022

### 继承


* extends
* super
* 扩展或重写方法


示例:子类继承父类



// 父类
class People {
    constructor(name) {
        this.name = name
    }
    eat() {
        console.log(`${this.name} eat food`);
    }
}

// 子类
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('夏洛', '2022')
console.log(xialuo.name) // 夏洛
console.log(xialuo.number) // 2022
xialuo.sayHi() // 姓名 夏洛, 学号 2022
xialuo.eat() // 夏洛 eat food

// 实例
const wanglaoshi = new Teacher('王老师', '语文')
console.log(wanglaoshi.name) // 王老师
console.log(wanglaoshi.major) // 语文
wanglaoshi.teach() // 王老师 教授 语文
wanglaoshi.eat() // 王老师 eat food

### JS原型(隐式原型和显式原型)


#### 类型判断 instanceof



console.log(xialuo instanceof Student) // true
console.log(xialuo instanceof People) // true
console.log(xialuo instanceof Object) // true

#### 原型


class 实际上是 **函数**



console.log(typeof Student) // 'function'
console.log(typeof Teacher) // 'function'
console.log(typeof People) // 'function'

#### 隐式原型和显式原型


* 隐式原型:`__prop__`
* 显式原型:`prototype`


实例对象的隐式原型等于对应构造函数的显示原型



console.log(xialuo.__proto__) // People {constructor: ƒ, sayHi: ƒ}
console.log(Student.prototype) // People {constructor: ƒ, sayHi: ƒ}
console.log(xialuo.__proto__ === Student.prototype) // true

**出处:https://coding.imooc.com/lesson/400.html#mid=30288**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/bc3ff06b39774b1ca02e70b1957e0bd0.png)


#### 原型关系


* 每个 class 都有一个显式原型 `prototype`
* 每个实例都有隐式原型 `__proto__`
* 实例的 `__proto__` 指向对应 class 的 `prototype`


#### 基于原型的执行规则


* 获取属性 xialuo.name 或执行方法 xialuo.sayHi 时
* 先在自身属性和方法寻找
* 如果找不到则自动去 `__proto__` 中查找


### 原型链


instanceof 顺着隐式原型往上找,找到返回 true,找不到返回 false


**出处:https://coding.imooc.com/lesson/400.html#mid=30289**


![在这里插入图片描述](https://img-blog.csdnimg.cn/964392dc1218457fa9aec556382b03f6.png)


#### hasOwnProperty


hasOwnProperty 会查找一个对象是否有某个属性,但是不会去查找它的原型链



console.log(xialuo.hasOwnProperty('name')) // true
console.log(xialuo.hasOwnProperty('eat')) // false

### 手写简易 jQuery


通过 class类 和 原型,手写 jQuery 部分功能



<p>第一段文字</p>
<p>第二段文字</p>
<p>第三段文字</p>

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) {
        
    }
}

测试:


![在这里插入图片描述](https://img-blog.csdnimg.cn/25431f8897e749118c0d982ebf29df05.png)


## 作用域和闭包


### 作用域


* 全局作用域
* 函数作用域
* 块级作用域


全局作用域:如 window 对象、document 对象  
 函数作用域:只能在函数里面使用  
 块级作用域:在块内有效


示例:**全局作用域**


在任何地方都能获取到



window.a = 'zhangsan'
function fn() {
    console.log(window.a)
}
fn() // zhangsan

示例:**函数作用域**


里面的函数能读取到外面函数的变量



function fn1() {
    let a = 'zhangsan'
    function fn2() {
        let b = 'lisi'
        console.log(a)
    }
    fn2()
}
fn1() // zhangsan

外面的函数不能读取里面函数的变量



function fn1() {
    let a = 'zhangsan'
    console.log(b)
    function fn2() {
        let b = 'lisi'
    }
    fn2()
}
fn1() // 报错:b is not defined

示例:**块级作用域**


在块之外读取不到变量



if (true) {
    let x = 100
}
console.log(x) // 报错:x is not defined

示例:创建 10 个 `<a>` 标签,点击的时候弹出来对应的序号



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)
}

![在这里插入图片描述](https://img-blog.csdnimg.cn/713db7603aba4bcc9129369b26bc6a27.png)


### 自由变量


* 一个变量在当前作用域没有定义,但被使用了
* 向上级作用域,一层一层依次寻找,直至找到为止
* 如果到全局作用域都没找到,则报错 xx is not defined


示例:不在当前作用域的就一层层往上找,a、b 都要往上层找



let a = 1
function fn1() {
    let b = 2
    function fn2() {
        let c = 3
        console.log(a + b + c)
    }
    fn2()
}
fn1() // 6

### 闭包


作用域应用的特殊情况,有两种表现:


* 函数作为返回值被返回
* 函数作为参数被传递


总结:**所有自由变量的查找,是在函数定义的地方,向上级作用域查找,不是执行的地方**


示例:函数作为返回值



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


* 作为普通函数:指向 window
* 使用 call apply bind :传入什么绑定什么([call、apply、bind的区别](https://bbs.csdn.net/topics/618545628))
* 作为对象方法被调用:指向当前对象本身,异步指向 window,箭头函数的异步指向上级作用域
* 在 class 方法中调用:指向当前实例本身
* 箭头函数:取上级作用域 this 的值


注:**this 的取值是在函数执行的时候确定的,不是在函数定义的时候确定的**


示例 1:普通函数、使用 call、apply、bind



function fn1() {
    console.log(this)
}
fn1() // window

示例 2:call、apply、bind 指定指向



function fn1() {
    console.log(this)
}
fn1() // window

fn1.call({x: 100}) // {x: 100}

const fn2 = fn1.bind({x: 200})
fn2() // {x: 200}

示例 3:作为对象方法被调用、箭头函数



const zhangsan = {
    name: 'zhangsan',
    sayHi() {
        console.log(this)
    },
    wait() {
        setTimeout(function() {
            console.log(this)
        })
    },
    waitAgain() {
        setTimeout(() => {
            console.log(this)
        })
    }
}
zhangsan.sayHi() // this即当前对象
zhangsan.wait() // this === window
zhangsan.waitAgain() // this即当前对象

![在这里插入图片描述](https://img-blog.csdnimg.cn/a172dfdba852494698c630342069dbff.png)


示例 4:在 class 方法中调用



class People {
    constructor(name) {
        this.name = name
    }
    sayHi() {
        console.log(this)
    }
}
const zhangsan = new People('张三')
zhangsan.sayHi() // this 指向张三对象

![在这里插入图片描述](https://img-blog.csdnimg.cn/189772b2e486425e9a8cb28f1311bcdd.png)


### 手写 bind


* 在函数原型上添加 bind1 方法,模拟 bind
* 将参数拆解为数组
* 通过 shift 方法挖走数组的第一项作为 this
* 把 this 赋值给 self,指向调用 bind 方法的函数
* 最后返回一个函数



// 模拟 bind
Function.prototype.bind1 = function() {
    // 将参数拆解为数组
    // const args = Array.prototype.slice.call(arguments)
    const args = Array.from(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)

![在这里插入图片描述](https://img-blog.csdnimg.cn/042e0ca614ed430bbb7ed85a1a5e5ead.png)


### 实际开发中闭包的应用


* 隐藏数据
* 如做一个简单的 cache 工具



// 闭包隐藏数据,只提供 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')) // 100

## 异步


### 同步和异步的不同


#### 单线程和异步


* JS 是单线程语言,只能同时做一件事
* 浏览器和 nodejs 已支持 JS 启动进程,如 Web Worker
* JS 和 DOM 渲染共用同一个线程,因为 JS 可修改 DOM 元素
* 遇到等待(网络请求,定时任务)不能卡住
* 需要异步
* 回调 callback 函数形式


#### 异步和同步


* 基于JS是单线程语言
* 异步不会阻塞代码执行
* 同步会阻塞代码执行


异步:callback 回调函数,等主线程任务执行完再执行



console.log(100)
setTimeout(() => {
    console.log(200)
}, 100)
console.log(300)
// 输出顺序:100 300 200

同步:按顺序执行,前面没执行完后面的不会执行



console.log(100)

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

络请求,定时任务)不能卡住

  • 需要异步
  • 回调 callback 函数形式
异步和同步
  • 基于JS是单线程语言
  • 异步不会阻塞代码执行
  • 同步会阻塞代码执行

异步:callback 回调函数,等主线程任务执行完再执行

    console.log(100)
    setTimeout(() => {
        console.log(200)
    }, 100)
    console.log(300)
    // 输出顺序:100 300 200

同步:按顺序执行,前面没执行完后面的不会执行

    console.log(100)


[外链图片转存中...(img-YHQvyHie-1714807523076)]
[外链图片转存中...(img-Tc8m0cQs-1714807523077)]

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618545628)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值