1.值类型与引用类型的区别?
常见值类型
let a
let str = 'string'
let num = 100
let bool = true
let s = Symbol('s')
常见引用类型
const obj = { age: 10 }
const arr = [21, 2 ,2 ,21]
const n = null
function fn() {}
let a = 100
let b = a
a = 200
console.log(b)
let a = { age: 20 }
let b = a
b.age = 21
cosnole.log(a.age)
区别?
1. 值类型存储到栈内存中
2. 引用类型存储到堆内存中
(1)typeof 能判断哪些类型?
let a
let str = 'string'
let num = 100
let bool = true
let s = Symbol('s')
typeof console.log
typeof function(){}
typeof null
typeof [wq,e]
typeof { a: 100 }
(2)何时使用=== 何时使用 ==
const obj = { x: 100 }
if (obj.a == null) {}
2.手写js深拷贝?
const obj = {
age: 20,
name: 'John',
address: {
city: '成都'
},
arr: [2,13,12,312]
}
function deepClone(obj = {}) {
if (typeof obj !== 'object' || obj == null) {
return obj;
}
let data
if (obj instanceof Array) {
data = []
} else {
data = {}
}
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
data[key] = deepClone(obj[key]);
}
}
return data
}
3.变量计算-注意某些类型转换的坑?
1.字符串拼接
const a = 100 + 10
const b = 100 + '10'
const c = true + '10'
2.==
100 == '100'
0 == ''
0 == false
false == ''
null == undefined
const obj = { x: 100 }
if (obj.a == null) {}
3.if语句和逻辑运算
truly 变量: !!a === true 的变量
falsely变量: !!a === false 的变量
(1)以下是falsely 变量.除此之外都是truly
!!0 === false
!!NaN === false
!!'' === false
!!null === false
!!undefined === false
!!false === false
(2)if 语句 if判断的就是truly变量
const a = true 或者 const a = 100
if (a) {
}
const b = '' 或者 const b = null
if (b) {
}
(3)逻辑运算
console.log(10 && 0)
console.log(0 && 10)
console.log('' || 'abc')
console.log('abc' || '')
console.log(!window.abc)
4.变量类型相关面试题
5.js原型的考点和面试题
(1)如何判断一个变量是不是数组?
使用 instanceof
[] instanceof Array
(2)手写一个简易的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() {
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)
})
}
}
const $p = new Jquery('p')
$p.get(1)
$p.each((elem) => console.log(elem.nodeName))
$p.on('click', () => alert('clicked'))
Jquery.prototype.dialog = function (info) {
alert(info)
}
class myJquery extends Jquery {
constructor(selector) {
super(selector)
}
addClass(className){}
style(data){}
}
(3)class的原型本质,怎么理解?
class是面向对象语法的实现,class它本质上类似于一个模板,通过模板构建一个东西,通过constructor赋值上一些属性及方法
class Student {
constructor(name, number) {
this.name = name
this.number = number
}
sayHi() {
console.log(`姓名${this.name},学号${this.number}`);
}
study() {
}
}
const zhangsan = new Student('name', 101)
console.log(zhangsan.name);
console.log(zhangsan.number);
zhangsan.sayHi();
6.如何用class实现继承
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 zhangsan = new Student('Amorous', 101)
console.log(zhangsan.name);
console.log(zhangsan.number);
zhangsan.sayHi();
zhangsan.eat();
const lisi = new Teacher('Amorous老师', '数学')
console.log(lisi.name);
console.log(lisi.major);
lisi.teach();
7.如何理解js原型(隐式原型和显示原型)?
typeof People
typeof Student
console.log(zhangsan.__proto__);
console.log(Student.prototype);
console.log(zhangsan.__proto__ === Student.prototype);
1.每个class都有显示原型 prototype
2.每个实例都有隐式原型__proto__
3.实例的__proto__ 指向对应 class的prototype
获取属性zhangsan.name或执行方法zhangsan.sayHi()时
先在自身属性和方法寻找
如果找不到则自动去__proto__中查找
8.instanceof是基于原型链实现的
9.js原型相关面试题
10.什么是作用域?
1.就是`编程语言`在变量中`存储值`,并且能`读取`和`修改`此值。在变量中`存值`和`取值`的能力,给程序`赋予了状态`。
2.如果没有这样的一个概念(规则), 程序虽然可以执行一些任务,但是它们将会受到极大的限制
3.为了解决这一问题就需要制定一些规则,这个规则就是`作用域`。
(1)全局作用域
var a = 132;
b = 123;
console.log(a, 'a');
console.log(b, 'b');
function test() {
c = 'wqe'
}
test();
(2)函数作用域
function test() {
var a = 12
return a + 5
}
console.log(test());
console.log(a);
(3)块级作用域
if(true){
let x = 100
}
console.log(x);
(4) 自由变量
1.一个变量在当前作用域没有定义,但被使用了
2.向上级作用域,一层一层依次寻找,直到找到为止
3.如果到全局作用域都没找到,则报错xx is not defined
let a = 0
function fn1 () {
let a1 = 100
function fn2 () {
let a2 = 200
function fn3 () {
let a3 = 300
return a + a1 + a2 + a3
}
fn3()
}
fn2
}
fn1()
11.什么是闭包?应用场景?
(1)什么是闭包?
1.闭包其实就是作用域应用时候的一个特殊情况
1.函数作为参数被传递
function printf (fn) {
let a = 100
fn()
}
let a = 200
function fn () {
console.log(a)
}
printf(fn)
2.函数作为返回值被返回
function create () {
let a = 100
return function () {
console.log(a)
}
}
let fn = create()
let a = 200
fn()
(2)闭包应用场景?
1.隐藏数据
2.比如做一个简单地缓存(cache)工具
function createCache() {
const data = {}
return {
set: (key, value) => {
data[key] = val
},
get: (key) => {
return data[key]
}
}
}
data.x = 200
const x = createCache()
x.set('a', 100)
console.log(x.get('a'));
12.this有几种赋值情况?
(1)this的不同应用场景,如何取值?
(2)手写bind函数?
13.作用域相关的面试题
14.同步和异步有何不同?
区别: 异步是基于JS是单线程语言,异步不会阻塞代码执行,同步会阻塞代码执行
同步?
1.js是单线程语言,只能同时做一件事儿
2.浏览器和node.js 已支持js启动进程,如Web Worker
3.JS和DOM渲染共用同一个线程,因为JS可修改DOM结构
4.遇到等待(网络请求,定时任务) 不能卡住
console.log(100)
alert(789)
console.log(200)
异步?
1.异步是基于callback函数形式
console.log(100)
setTimeout(() => {
console.log(200)
}, 1000)
console.log(300)
15.异步应用场景有哪些?
1.网络请求,如ajax图片加载
console.log('start')
$p.get('./data1.json', (data) => {
console.log(data);
})
console.log('end');
function loadImg(src) {
const p1 = new Promise((resolve, reject) => {
const img = document.createElement('img')
img.onload = () => {
resolve(img)
}
img.onerror = () => reject(new Error(`图片加载失败${src}`))
img.src = src
})
return p1
}
const url = 'https://54584c6d0001664502200220-140-140.jpg'
loadImg(url).then(img => {
console.log(img.width);
return img
}).then(img => {
console.log(img.height);
}).catch(err => {
console.error(err);
})
2.定时任务,如setTimeout(一次),setInterval(循环)
console.log(1)
setTimeout(() => {
console.log(2)
}, 1000)
console.log(3)
setTimeout(() => {
console.log(4)
}, 0)
console.log(5)
16.promise的基本使用
$.get(url1, (data1) => {
console.log(data1);
$.get(url1, (data2) => {
console.log(data2);
$.get(url1, (data3) => {
console.log(data3);
})
})
})
function getData(url) {
return new Promise((resolve, reject) => {
$.ajax({
url,
success(data){
resolve(data)
},
error(err){
reject(err)
}
})
})
}
const url1 = '/data1.json'
const url2 = '/data2.json'
const url3 = '/data3.json'
getData(url1).then(data1 => { 使用.then可以一直链式调用下去
console.log(data1);
return getData(url2)
}).then(data2 => {
console.log(data2);
return getData(url3)
}).then(data3 => {
console.log(data3);
}).catch(err => console.error(err))