new 以及 call、apply、bind 关键字解析
1.new关键字
-
自动创建对象:使用
new
调用构造函数时,会自动创建一个空对象,并将其赋值给this
。你不需要显式地使用{}
来创建对象。 -
绑定
this
到新对象:构造函数内部的this
指向新创建的对象,因此可以在构造函数中为新对象添加属性和方法。 -
继承原型链:新对象会继承构造函数的
prototype
属性所指向的对象。这意味着所有通过new
创建的实例都可以访问原型上的属性和方法。 -
隐式返回新对象:构造函数默认返回新创建的对象。如果构造函数中有显式的返回值,只有当返回的是一个对象时才会覆盖默认行为;如果返回的是原始类型(如字符串、数字等),则仍然返回新创建的对象。
-
构造函数必须使用
new
调用:如果忘记使用new
调用构造函数,this
将指向全局对象(浏览器环境中是window
,严格模式下是undefined
),这可能会导致意外的行为和错误。
function Preson() {this.name = 'gauseen'return { age: 18 }
}let p = new Preson()
console.log(p) // 函数中主动返回了一个对象,所以打印是 {age: 18}
console.log(p.name) // 返回的是{age: 18} ,所以没有name属性 undefinedfunction Preson1() {this.name = 'gauseen'return 'tom'
}let p = new Preson1()
console.log(p) // 主动返回的不是对象,所以还是执行默认行为 Preson1 {name: 'gauseen'}
console.log(p.name) // gauseen
2.call
、apply
和 bind
的相同点
- 改变函数的 this 指向:三者都可以用来改变函数内部的
this
指向,使得函数可以在不同的上下文中执行。 - 继承原函数的作用域:调用时会继承原函数的作用域链。
3.不同点
let a = {name: '梦见月',age: 18,getName: function (msg) {return msg + this.name},
}let b = {name: '芙宁娜',
}console.log(a.getName('hi!')) // hi!梦见月console.log(a.getName.call(b, 'hi!')) // hi!芙宁娜console.log(a.getName.apply(b, ['hi!'])) // hi!芙宁娜let getNowName = a.getName.bind(b, 'hi!') // 通过bind改变this指向执行时用方法执行
console.log(getNowName()) // hi!芙宁娜
其实没那么难理解,就是借用的概念,一个对象上没有想用的方法,那就借用别人的方法
4.使用场景
1.类数组借用
let a = {0: '弗洛伊德',1: '阿基维利',length: 2,
}Array.prototype.push.call(a, '叔本华', '东野圭吾')
console.log(a) // [ '弗洛伊德', '阿基维利', '叔本华', '东野圭吾' ]
2.求数组最大值
let a = [1, 2, 3, 4, 56, 7, 99, 6, 1]console.log(Math.max(...a)) // 99
console.log(Math.max.apply(Math, a)) // 99
5.手写 apply、cal l和 bind
let a = [1, 2, 3, 4, 56, 7, 99, 6, 1]// 自定义 call 方法
Function.prototype.myCall = function(context, ...args) {context = context || windowconst fn = Symbol('fn')context[fn] = thisconst result = context[fn](...args)delete context[fn]return result
}// 自定义 apply 方法
Function.prototype.myApply = function(context, args) {context = context || windowconst fn = Symbol('fn')context[fn] = thisconst result = context[fn](...args)delete context[fn]return result
}// 自定义 bind 方法
Function.prototype.myBind = function(context, ...args) {const self = thisreturn function(...newArgs) {return self.myCall(context, ...args, ...newArgs)}
}console.log(Math.max.myCall(Math, ...a))
console.log(Math.max.myApply(Math, a))
console.log(Math.max.myBind(Math)(...a))