Web前端高频面试题解析(javascript篇)--- 每日十题(3)

发布于:2023-01-20 ⋅ 阅读:(4) ⋅ 点赞:(0) ⋅ 评论:(0)

目录

1.DOM和BOM

1.DOM

2.BOM

2.函数中的arguments类数组

1.为什么函数的arguments参数是类数组而不是数组?

1.类数组

 如何遍历类数组?

1.通过for循环

2.将数组的方法应用到类数组上,

3.将类数组转化成数组

4.使用展开运算符将类数组转化成数组

3.判断一个对象是否属于一个类

两种方法 

1.instanceof

2. 对象的属性constructor来判断,指向该对象的构造函数

4.forEach和map方法区别

1.遍历数组

1.两者无区别:不会更改原数组 

 2.两者有区别:返回值不一样

2.区别:

5.使用for...of来遍历对象

1.第一种:

2.第二种:

3.iterator遍历过程

6.数组的遍历方法

1.forEach

2.map

3.filter

4.for...of

5.reduce

7.对原型的理解

1.prototype属性

 2.显示原型和隐式原型

总结:

8.对原型链的理解

9.对原型的修改和重写

1.修改原型

2.重写原型

10.for...of和for...in的区别

1.遍历对象

区别:

2.遍历数组

 区别:

3.总结:

1.for...in:

2.for..of:


1.DOM和BOM

1.DOM

DOM:document,文档对象类型,用来获取或者设置文档标签的属性。

JS可以通过DOM获取到哪些标签,标签有哪些属性,内容有哪些

DOM操作的对象是文档,所以DOM和浏览器没有关系,因为它关注网页本身的内容 。

2.BOM

BOM:brower object model,浏览器对象模型

 提供独立于内容面和浏览器窗口进行交互的对象。

管理窗口与窗口之间的通讯,核心对象是window-->location(用于url相关的操作),history(用于历史相关的操作),navigator(包含了浏览器相关的信息)

BOM是控制浏览器行为的api,DOM是一个页面结构的api。

2.函数中的arguments类数组

1.为什么函数的arguments参数是类数组而不是数组?

1.类数组

与数组相似,但是没有数组常见的方法属性。

function func () {
      console.log(arguments)
}
func(1, 2, 3, 4, 5, 5)

 如何遍历类数组?

1.通过for循环

function func () {
      console.log(arguments)
      for (let i = 0; i < arguments.length; i++) {
        console.log(arguments[i])//1 2 5
      }
}
func(1, 2, 5)

2.将数组的方法应用到类数组上,

使用call和apply,使用forEach方法(数组的方法)

call:调用一个对象的一个方法,以另一个对象替换当前的对象。

function fun1 () {
      Array.prototype.forEach.call(arguments, (item) => {
        console.log(item)//1 2 3
      })
}
fun1(1, 2, 3)

3.将类数组转化成数组

使用Array.from(),对一个类数组,创建一个新的数组实例。

 function fun2 () {
      const arr = Array.from(arguments)
      console.log(arr)//(3) [1, 2, 3]
      arr.forEach((item) => {
        console.log(item)// 1 2 3
      })
      arr.push(7)
      console.log(arr)//(4) [1, 2, 3, 7]
}
fun2(1, 2, 3)

4.使用展开运算符将类数组转化成数组

function fun3 () {
      const arr1 = [...arguments]
      console.log(arr1)//(3) [7, 17, 27]
      //把数据遍历出来
      arr1.forEach((item) => {
        console.log(item)//7 17 27
      })
}
fun3(7, 17, 27)

3.判断一个对象是否属于一个类

类本身指向就是构造函数,类的数据类型就是函数。

function Person (name) {
      this.name = name
}
var obj = new Person('zz')

两种方法 

1.instanceof

判断构造函数的prototype属性是否出现在对象的原型链的任何位置。

function Person (name) {
      this.name = name
}
var obj = new Person('zz')
// obj是属于Person这个类的
console.log(obj instanceof Person)//true
// obj1不属于Person,因为它不是通过这个构造函数实例化构造出来的
var obj1 = {}
console.log(obj1 instanceof Person)//false

2. 对象的属性constructor来判断,指向该对象的构造函数

console.log(obj)
    // 可以通过
console.log(obj.constructor)//ƒ Person (name) {this.name = name}
    // 也可以通过
console.log(obj.__proto__.constructor)//ƒ Person (name) {this.name = name}

 不是很好,因为这个是作为这个对象的属性来进行操作的,这个属性是可以被修改

// 会更改,这里更改为Array
obj.__proto__.constructor = Array
console.log(obj.__proto__.constructor)//ƒ Array() { [native code] }

4.forEach和map方法区别

1.遍历数组

回调函数种有三个参数,第一个参数数组的遍历值(数组的元素值),第二个参数数组的索引值,第三个参数是数组的本身。  

1.两者无区别:不会更改原数组 

//map
var arr = [1, 2, 3]
arr.map((item, index, arr) => {
      console.log(item)//数组的遍历值
      console.log(index)//数组的索引值
      console.log(arr)//数组的本身
      // 不会更改原数组
      item *= 2//改数组的遍历值,不会
      arr[0] = 10//改数组的本身,就会进行更改
})
console.log(arr)

//forEach
var arr = [1, 2, 3]
arr.forEach((item, index, arr) => {
      console.log(item)//数组的遍历值
      console.log(index)//数组的索引值
      console.log(arr)//数组的本身
      // 不会更改原数组
      item *= 2//改数组的遍历值,不会
      arr[0] = 10//改数组的本身,就会进行更改
})
console.log(arr)

 2.两者有区别:返回值不一样

//map
var arr = [1, 2, 3]
var result = arr.map((item, index, arr) => {
      item *= 2
      arr[0] = 10
      // 会返回新数组,用新数组存放并且返回
      return index * 2
})
console.log(arr)//(3) [10, 2, 3]
console.log(result)//(3) [0, 2, 4]

//forEach
var arr = [1, 2, 3]
var result = arr.forEach((item, index, arr) => {
      item *= 2
      arr[0] = 10
      return index * 2
})
console.log(arr)//(3) [10, 2, 3]
console.log(result)//undefined

2.区别:

map分配内存空间存储新数组,并且返回;forEach不会返回执行结果,返回undefined。

5.使用for...of来遍历对象

ES6新增遍历方式,可以遍历数组和对象,并且能返回数组的元素和对象的属性值;而不像for循环通过下标或者属性名。

是允许遍历一个含有iterator接口的数据结构(数组,对象等)并且返回各项的值。

1.第一种:

需要遍历的对象是类数组对象,可以使用数组的Array.from将类数组转为数组 

var obj = {
      0: 1,
      1: 2,
      2: 9,
      length: 3
}
obj = Array.from(obj)
for (let value of obj) {
      console.log(value)// 1 2 9
}

2.第二种:

如果需要遍历的对象不是类数组,需要给对象添加一个Symbol.iterator属性,让它指向迭代器。

3.iterator遍历过程

1.创建一个指针对象,指向当前数据结构的起始位置

2.第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员

3.第二次调用指针对象的next方法,指针就指向数据结构的第二个成员

4.不断调用指针对象的next方法,直到它指向数据结构的结束位置

每一次调用next方法,都会返回数据结构的当前成员的信息,返回一个包含value和done两个属性的对象

value:当前成员的值;done:是一个布尔值,表示遍历是否结束。

var person = {
      name: 'zz',
      age: 10,
      height: 100
}
// 1.指针对象
person[Symbol.iterator] = function () {
  // 2.第二个成员
  // 拿到对象中的所有key值,返回的是数组
  // this谁调用了这个函数就指向谁(person)
  var keys = Object.keys(this)
  // 定义数组的下标值
  var index = 0
  return {
        next () {
          if (index < keys.length) {
            return { value: person[keys[index++]], done: false }
          } else {
            // 遍历完了
            return { value: undefined, done: true }
          }
        }
  }
}
for (let value of person) {
      console.log(value)//zz 10 100
}

6.数组的遍历方法

var arr = [1, 2, 3, 4]

1.forEach

不会改变原数组,没有返回值。

// 三个参数,遍历值,索引值,数组本身
let resultFor = arr.forEach((item, index, arr) => {
      // console.log(item)
      // console.log(index)
      // console.log(arr)
      return index * 2

})
console.log(resultFor)//undefined

2.map

不会改变原数组,有返回值。

let resultMap = arr.map((item, index, arr) => {
      // console.log(item)
      // console.log(index)
      // console.log(arr)
      return index * 2
})
console.log(resultMap)//(4) [0, 2, 4, 6]

3.filter

可以遍历数组也可以过滤数组。有返回值,返回包含符合条件的元素的数组。

let resultFilter = arr.filter((item) => {
      console.log(item)//1 2 3 4
      return item > 3
})
console.log(resultFilter)//[4]

4.for...of

返回的是数组的元素,对象的属性值。但是不能遍历普通的对象。

for (let value of arr) {
      console.log(value)//1 2 3 4
}

5.reduce

接收一个函数,作为一个累加器。

//其他方法的累加比较麻烦
var total = 0
for (let value of arr) {
      total += value
      console.log(value)//1 2 3 4
      console.log(total)//10
}

//reduce方法
// 函数有两个参数是必传参数,第一个计算之后返回的值或者初始值;第二个当前的元素
let resultReduce = arr.reduce((pre, item) => {
      // 初始值pre=0
      console.log('pre', pre)
      console.log('item', item)
      return pre + item
}, 0)
// let resultReduce把最后相加的值输出出来
console.log(resultReduce)//10

 

7.对原型的理解

1.prototype属性

默认对应着一个空对象(没有我们指定的方法和属性),这个空对象就是原型对象。每一个prototype都是不相等的。

function Person () {

}
console.log(Person.prototype)

 2.显示原型和隐式原型

每一个函数都有一个prototype属性,就是显示原型

每一个实例对象都会有一个__proto__,就是隐式原型

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

function Fun () {//内部语句:Fun(this).prototype={}
}
console.log(Fun.prototype)
var fun = new Fun()//内部语句:fun(this).__proto__=Fun.prototype
console.log(fun.__proto__)
console.log(Fun.prototype === fun.__proto__)//true

  

总结:

函数的prototype属性,在定义函数是自动添加的,默认值是一个空对象

对象的__proto__属性,创建对象的时候自动添加的,默认值是构造函数的prototype属性

8.对原型链的理解

查找对象的属性(方法)。

// 创建构造函数
function Fun () {//内部语句:Fun(this).prototype={}
      this.test1 = function () {
        console.log('test1()')
      }
}
// 添加test2方法
Fun.prototype.test2 = function () {
      console.log('test2()')
} 
console.log(Fun.prototype)//{test2: ƒ, constructor: ƒ}
// 实例化对象
var fun = new Fun()//内部语句:fun(this).__proto__=Fun.prototype
// 打印test1
fun.test1()//test1()
fun.test2()//test2()
console.log(fun.toString())//[object Object]
//toString()属于Object原型对象的方法
fun.test3()//fun.test3 is not a function

按照步骤路线查找即可

9.对原型的修改和重写

// 创建构造函数
function Person (name) {
      this.name = name
}

1.修改原型

修改原型没有影响。

//1.修改原型
Person.prototype.getName = function () {
      console.log(this.name)
}
// 实例化对象
var p = new Person('zz')
console.log(p.__proto__ === Person.prototype)//true
console.log(p.__proto__ === p.constructor.prototype)//true

2.重写原型

重写有影响,需要把constructor指向回来。

Person.prototype = {
      getName: function () {
        console.log(this.name)
      }
}
//直接给Person的原型对象用对象进行赋值时,p的构造函数指向根构造函数Object
var p = new Person('zz')//内部语句:p的隐式原型等于Person的显示原型p(this).__proto__=Person.prototype
console.log(p.__proto__ === Person.prototype)//true
    // 指向了Object,需要把constructor指向回来
    console.log(p.constructor)//ƒ Object() { [native code] }
console.log(p.__proto__ === p.constructor.prototype)//false
//指向回来
p.constructor = Person
console.log(p.__proto__ === p.constructor.prototype)//true

10.for...of和for...in的区别

1.遍历对象

for...of遍历获取对象的键值,for...in获取对象的键名。

function Person (name, age, sex) {
      this.name = name
      this.age = age
      this.sex = sex
}
// 构造函数原型上面去定义一个属性
Person.prototype.height = 111
var p = new Person('zz', 7, 'nan')
// 写iterater属性,获取Person,返回对象过去
p[Symbol.iterator] = function () {
      var keys = Object.keys(this)
      var index = 0
      return {
        next () {
          if (index < keys.length) {
            return { value: p[keys[index++]], done: false }
          } else {
            return { value: undefined, done: true }
          }
        }
      }
}

// 遍历
for (let value of p) {
      console.log(value)//zz 7 nan
}
for (let key in p) {
      console.log(key)//name age sex height
}

区别:

for...in会遍历对象的整个原型链,性能很差。

for...of只会遍历当前对象。

2.遍历数组

对于数组的遍历,for...in返回数组中所有可枚举的属性,for...of返回数组的下标对应的属性值。

var arr = [1, 2, 3, 4]
console.log(arr)//(4) [1, 2, 3, 4]
for (let i of arr) {
      console.log(value)//1 2 3 4
}
// for...in数组原型上面添加属性的话,也会遍历出来
Array.prototype.value = 50
for (let i in arr) {
      console.log(i)//0 1 2 3 value
}

 是数组,但有下标,像对象一样。

 

 区别:

for...in返回数组中所有可枚举的属性,

for...of返回数组的下标对应的属性值。

3.总结:

1.for...in:

主要是为了遍历对象而产生,不适用于遍历数组。

2.for..of:

循环可以用来遍历数组,类数组对象,字符串...


网站公告

欢迎关注微信公众号

今日签到

点亮在社区的每一天
签到