new
原理
用new实例化一个对象后,该对象会继承构造函数及其原型上的属性。可以发现其实new的操作也是一种继承,不过不是类与类之间的继承,而是实例与类之间的继承。
那么 new 在这个生成实例的过程中到底进行了哪些步骤来实现呢?总结下来大致分为以下几个步骤。
function Person(){
this.name = 'Jack';
}
var p = new Person();
console.log(p.name) // Jack
- 创建一个新对象;
- 将构造函数的作用域赋给新对象(this 指向新对象);
- 执行构造函数中的代码(为这个新对象添加属性);
- 返回新对象。
手写一个new
```javascript function new() { let obj = {} // 生成一个空对象 let Constructor = [].shift.call(arguments) // 获取第一个参数(构造函数) obj._proto = Constructor.prototype // 对象继承构造函数原型属性方法 let result = Constructor.apply(obj, arguments) // 对象this指向构造函数(继承构造函数的属性和方法) return typeof result === ‘object’ ? result : obj // 确保返回的是一个对象 }
function Person(name) { this.name = name; this.say = function () { console.log(‘my name is ‘ + name); } } Person.prototype.type = ‘人’ let person = new Person(‘hkj’) let person1 = _new(Person,’hkj’) console.log(person) console.log(person1)
`applay,``call`,`bind`都可以改变函数的 this 指向。<br />apply 和 call 的区别在于,传参的写法不同:apply 的第 2 个参数为数组; call 则是从第 2 个至第 N 个都是给 函数的传参;而 bind 和这两个(call、apply)又不同,bind 虽然改变了 func 的 this 指向,但不是马上执行,而这两个(call、apply)是在改变了函数的 this 指向之后立马执行。
```javascript
var name = 'name'
var obj = {
name: 'objName'
}
function getName(p1, p2) {
console.log(p1, p2,this.name)
}
getName(1, 2) //1 2 "name"
getName.applay(obj, [1, 2])//1 2 "objName"
getName.call(obj, 1, 2)//1 2 "objName"
applay
apply接收的第一个参数是this,第二个参数是 所需参数所组成的数组。 (中括号内的是可选参数,可写可不写)
Function.apply(obj[,argArray])
applay模拟实现
function myApply(context) {
if (typeof this !== 'function') {
throw new TypeError('Error');
}
context = context || window;
context.fn = this;
var result;
if (arguments[1]) {
result = context.fn(...arguments[1]);
} else {
result = context.fn();
}
delete context.fn;
return result;
}
// 验证
var name = 'name'
var obj = {
name: 'objName'
}
function getName(p1, p2) {
console.log(p1, p2,this.name)
}
Function.prototype.myApply = myApply
getName.myApply(obj,[ 1, 2])//1 2 "objName"
call
- 明确是谁调用call:函数。
- call接收的第一个参数是要改变的this指向(去执行这个函数)。若无指定,默认为window
- call接收的后续参数就是作为调用call的那个函数所需的参数。 ```javascript function myCall(context) { //判断一下 if (typeof this !== ‘function’){ throw new TypeError(‘error’) } //this指向,谁去执行去这个函数 context = context || window //要执行的函数 context.fn = this //取出参数 const args = […arguments].slice(1) //执行函数 const result = context.fn(…args) //删除fn delete context.fn return result }
Function.prototype.myCall = myCall getName.myCall(obj, 1, 2)//1 2 “objName”
<a name="SvuL6"></a>
# bind
bind 方法 与 apply 和 call 比较类似,也能改变函数体内的 this 指向。不同的是,**bind 方法的返回值是函数**,并且需要稍后调用,才会执行。而 apply 和 call 则是立即调用。
```javascript
function myBind(context) {
if (typeof this !== 'function') {
throw new TypeError('Error')
}
const _this = this
const args = [...arguments].slice(1)
// 返回函数
return function F() {
// 1 判断是否用作构造函数
if (this instanceof F) {
return new _this(...args, ...arguments)
}
// 2 用作普通函数
return _this.apply(context, args.concat(...arguments))
}
}
// 验证
var name = 'name'
var obj = {
name: 'objName'
}
function test(p1, p2){
this.a = p1
this.b = p2
console.log(this.name,p1, p2)
}
Function.prototype.myBind = myBind
var f1 = test.myBind(obj, 1)
f1(2)//objName 1 2