new、apply、bind、call实现的底层逻辑
思考
- 用什么样的思路可以实现 new 关键字
- apply、call、bind 这三个方法之间有什么区别?
- 怎样实现一个 apply 或者 call 的方法
new
new 关键字的主要作用 : 就是执行一个构造函数,返回一个实例对象,根据构造函数的情况,来确定是否可以接受参数的传递
function Person() {
this.name = 'Jack'
}
const p = new Person()
console.log(p.name); // 'Jack'
function Person1() {
this.name = 'Jack'
return {
age : 18
}
}
const p1 = new Person1()
console.log(p1.name); // undefined
console.log(p1.age); // 18
const p2 = Person()
console.log(p2); // undefined
上述代码 new 关键词实际上进了四个步骤:
创建了一个新的对象将构造函数的作用域赋給这个新对象(使this指向这个新对象)执行构造函数中的代码(为这个新对象添加属性)返回新对象
new 关键词执行之后总是会返回一个对象,要么是实例对象 要么是return语句指定的对象
apply & call & bind 原理介绍
==call== 、==apply== 和 ==bind== 是挂在Function 对象上的三个方法
调用这三个方法必须是一个函数
func.call(thisArg, p1, p2, ...)
func.aplly(thisArg, [p1, p2, ...])
func.bind(thisArg,p1,p2,...)
==call== 、==apply== 和 ==bind== 都可以改变函数内的this指向,但是用法有所不同,apply的第二个形参是数组的形式,call、bind调用后是立刻执行,bind是返回一个新的函数并不会立刻执行
const a = {
name: 'jack',
age: 18,
getName: function(msg) {
return msg + this.name
}
}
const b = {
name: 'lili',
}
console.log(a.getName('hi~ '));// hi~ jack
console.log(a.getName.call(b, 'hi~~'));// hi~~lili
console.log(a.getName.apply(b, ['hi~~~!']));// hi~~~!lili
const newfunc = a.getName.bind(b, 'hello ')
console.log(newfunc()); // hello lili
应用场景
- ==判断数据类型 Object.prototype.toString 几乎可以判断所有类型的数据==
Object.prototype.toString.call('123')
-
==类数组不是真正的数组,无法使用一些数组类型自带的方法,就得使用一些方法去借用数组的方法==
-
==获取数组的最值==
const arr = [1,2,41,2,1,-1,0,8,-99,76] const max = Math.max.apply(Math,arr) const min = Math.min.apply(Math, arr) console.log(max); console.log(min); -
==继承==
new的实现
==new被调用后大致做了哪几件事情==
- 让实例可以访问私有属性
- 让实例可以访问构造函数的原型所在原型链上的属性
- 构造函数返回的最后结果是引用数据类型
function _new(ctor, ...args) {
if (typeof ctor !== 'function') {
throw 'ctor must be a function'
}
const obj = new Object()
obj.__proto__ = Object.create(ctor.prototype)
const res = ctor.apply(obj, ...args)
const isObj = typeof res === 'object' && res !== 'null'
const isFunc = typeof of === 'function'
return isObj || isFunc ? res : obj
}
call、apply的实现
Function.prototype.call = function(context,...args) {
const context = context || window
context.fn = this
const res = eval('context.fn(...args)')
delete context.fn
return res
}
Function.prototype.apply = function(context,...args) {
const context = context || window
context.fn = this
const res = eval('context.fn(...args)')
delete context.fn
return res
}
bind的实现
Function.prototype.bind = function(context, ...args) {
if (typeof this !== 'function') {
throw 'this must be a function'
}
const self = this
const found = function() {
self.apply(this instanceof self ? this : context,
args.concat(Array.prototype.slice.call(arguments))
)
}
if (this.prototype) {
found.prototype = Object.create(this.prototype)
}
return found
}