面试题【Day10】

2021-09-06  本文已影响0人  小王子__

本篇绪论

1, call、apply、bind

2, Object.create()

3,JS中的new操作符的原理

1,call、apply、bind

三者都是改变this指向的方法

call

fn.call: 当前实例(函数fn)通过原型链的查找机制找到function.prototype上的call方法,把找到的call方法执行,当call方法执行的时候内部处理了一些事情:

1,首先把要操作的函数中的this关键字变成call方法第一个传递的实参

2,把call方法第二个及之后的实参获取到

3,把要操作的函数执行,并且把第二个以后的实参传递给函数

fn.call(this, param...)

非严格模式下:如果不传参数,或者第一个参数是null或undefined,this都指向window

let fn = function(a,b) {
  console.log(this, a, b)
}
let obj = {name: 'xiaowang'}
console.log(fn.call(obj, 1, 2)  // this:obj a:1 b:2
console.log(fn.call(1,2))  // this:1 a:2 b:undefined
console.log(fn.call(1))  // this:1 a: undefined b:undefined
console.log(fn.call()) // this:window a:undefined b:undefined
console.log(fn.call(null)) // this:window a:undefined b:undefined
console.log(fn.call(undefined)) // this:window a:undefined b:undefined

严格模式下:
第一个参数是谁,this就指向谁,包括null和undefined,如果不传参数this就是undefined

"use strict"
let fn = function(a,b) {
  console.log(this, a, b)
}
let obj = {name: 'xiaowang'}
console.log(fn.call(obj, 1, 2))  // this:obj a:1 b:2
console.log(fn.call(1,2))  // this:1 a:2 b:undefined
console.log(fn.call(1))  // this:1 a: undefined b:undefined
console.log(fn.call()) // this:undefined a:undefined b:undefined
console.log(fn.call(null)) // this:null a:undefined b:undefined
console.log(fn.call(undefined)) // this:undefined a:undefined b:undefine
apply

和call基本一致,唯一区别在于传参方式不同:
apply把需要传递给fn的参数放到一个数组(或者类数组)中传递进去

fn.call(obj, 1,2)
fn.apply(obj, [1,2])

类数组(伪数组):是指在写法上跟数组一样,比如arguments,函数的第一个参数是arguments[0],写法上跟数组一样,但是不是数组,它的原型是Object

function fn() {
  console.log(arguments)
}
fn(1,2,3,4,5,6) 
image

以上代码打印出来它的构造函数是Object,只不过这个对象的key值是0,1....写出来之后类似数组的下标,所以叫类数组

类数组转数组方法:

function fn() {
  // // 1, for循环
  const arr = []
  for (var i = 0; i < arguments.length; i++) {
    arr.push(arguments[i])
  }

  // 2, Object.values
  const arr = Object.values(arguments)

  // 3, for of
  const arr = []
  for (var key of arguments) {
    arr.push(arguments[key])
  }

  // 4, for in
  const arr = []
  for (var i in arguments) {
    arr.push(arguments[i])
  }

  // 5, Array.from
  const arr = Array.from(arguments)

  // 6, slice
  const arr = Array.prototype.slice.call(arguments)

  // 7, 扩展运算符
  console.log([...arguments])
}
fn(1,2,3,4,5,6)
bind

语法和call基本一样,区别在于立即执行还是等待执行

fn.call(obj, 1,2)  // 改变fn中的this, 并且把fn立即执行
fn.bind(obj, 1,2)  // 改变fn中的this, fn并不执行

2, Object.create()

语法Object.create(proto, [propertiesObject])

通过Object.create()可以创建对象,接受两个参数,第一个是对象,第二个是该对象的属性设置

const obj = Object.create({}) // {} 可以这样创建对象
const obj = Object.create({}, {
  "name": {value: 'xiaowang'},
  "age": {value: 18}
})  // {name: 'xiaowang', age: 18}
const person = {
  name: 'xiaowang',
  sayName () {
    console.log(`${this.name}`)
  }
}
const p1 = Object.create(person)
console.log(p1)
image
const person = {
  name: 'xiaowang',
  age: 18,
  sayName () {
    console.log(`${this.name}`)
  }
}
const p1 = Object.create(person)
p1.name = 'xiaoma'  // name是p1的属性不是person的属性
p1.age = 20
p1.sayName()
console.log(p1)
image
创建一个新对象p1,使用person对象来提供新创建的对象的proto

实现单个继承:

function Person(name, age) {
  this.name = name
  this.age = age
}
Person.prototype.getName = function () {
  return this.name
}
Person.prototype.getAge = function () {
  return this.age
}
function Student(name, age, grade) {
  Person.call(this, name, age)
  this.grade = grade
}
Student.prototype = Object.create(Person.prototype, {
  constructor: {
    value: Student
  },
  foo: {
    writable: true,
    configurable: true,
    value: 'hello'
  },
  getGrade: {
    value: function() {
      return this.grade
    }
  }
})

var p1 = new Student('xiaowang', 18, 100);
console.log(p1.getName())  // xiaowang
console.log(p1.getAge())  // 18
console.log(p1.getGrade())  // 100
console.log(p1.foo)  // hello

3,JS中的new操作符原理

JS中new操作符用于创建一个给定构造函数的对象实例

function Person(name, age) {
  this.name = name
  this.age = age
}
const p1 = new Person('xiaowang', 18)
console.log(p1) //Person{name: 'xiaowang', age: 18}
image

以上我们定义了一个构造函数Person,然后通过new操作符生成Person构造函数的一个实例,并将其引用赋值给变量p1。可以看到该实例对象具有name、age属性,它们的值就是我们调用构造函数传入的值。

new关键字进行的操作

自己实现new操作符
function myNew(constrc, ...args) {
  // 1,2 创建一个obj对象, 将obj的[[prototype]]属性指向构造函数的原型对象,即: obj.__proto__ === constructor.prototype
  const obj = Object.create(constrc.prototype)
  // 3,将constrc内部的this,(即执行上下文)指向obj,并执行
  const result = constrc.apply(obj, args)
  // 4,如果构造函数返回的是对象,则使用构造函数执行的结果,否则,返回新创建的对象
  return result instanceof Object ? result : obj
}
function Person(name, age) {
  this.name = name
  this.age = age
}
const p1 = myNew(Person, 'xiaownag', 18)
console.log(p1)  // Person{name: 'xiaowang', age: 18}
上一篇 下一篇

猜你喜欢

热点阅读