本篇绪论
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)

以上代码打印出来它的构造函数是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并不执行
- 1,拥有length属性
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)

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)

创建一个新对象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}

以上我们定义了一个构造函数Person,然后通过new操作符生成Person构造函数的一个实例,并将其引用赋值给变量p1。可以看到该实例对象具有name、age属性,它们的值就是我们调用构造函数传入的值。
new关键字进行的操作
- 1, 创建一个空对象obj({})
- 2, 将obj的[[prototype]]属性指向构造函数constructor的原型,即:obj.[[prototype]] = constructor.prototype
- 3, 将构造函数constructor内部的this绑定到新建的对象obj上,执行constructor(跟调用普通函数一样,只是此时函数的this为新创建的对象obj而已,就好像执行obj.constructor()一样)
- 4, 如果构造函数没有返回非原始值(即不是引用类型的值),则返回该新建的对象obj(默认会添加return this)。否则,返回引用类型的值
自己实现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}
网友评论