new 操作符干了什么?
- 创建一个新对象
- 对象连接到构造函数原型上
- 执行构造函数代码,并绑定 this(为这个新对象添加属性)
- 返回新对象
手写简版new函数
更简版function myCreate() {
// 创建一个空对象
const obj = new Object()
// 获取到构造器
const constructor = Array.from(arguments).shift();
// 继承构造器上原型
obj.__proto__ = constructor.prototype;
// 通过call函数将this绑定到obj上,并添加属性
constructor.call(obj, ...Array.from(arguments).slice(1))
// 返回this
return obj;
}
function yourCreate(constructor, ...args){
const obj = Object.create(constructor.prototype);
constructor.apply(obj,args)
return obj
}
使用
```javascript function Person(name, age, gender ) { this.name = name; this.age = age; this.gender = gender; }
Person.prototype.introduce = function () {
console.log(name: ${this.name}
age: ${this.age}
gender: ${this.gender? '男': '女'}
)
}
const human = myCreate(Person, ‘长青’, 23, true) human.introduce()
<a name="hFyrL"></a>
### 实现Instanceof方法
大概思路就是能否目标对象原型链上查找到需判断的构造函数
```javascript
function myInstanceof(targetObj, ctor) {
// 如果是基本数据类型直接返回
if (typeof targetObj !== 'object' || targetObj === null) {
return false
}
// 获取目标对象原型
let proto = Object.getPrototypeOf(targetObj)
// 判断原型对象上的构造函数 与需要检查的构造函数是否相同
if (proto.constructor === ctor) return true
// 在原型链上查找是否存在需要判断的构造函数
while (proto !== null) {
if (proto.constructor === ctor) return true
proto = Object.getPrototypeOf(proto)
}
return false
}
class Aaa extends Array {
constructor(name){
super()
this.name = name
}
}
console.log(myInstanceof(new Aaa('长青'), Array))
改变this的方法有哪些以及它们的区别
改变this的方法有 bind、 call、 apply,区别在于调用它们的方式不同
- apply:接受两个参数,第一个参数是this的指向,第二个参数是函数接受的参数,以数组的形式传入改变this指向后原函数会立即执行,且此方法只是临时改变this指向一次。
- call方法的第一个参数也是this的指向,后面传入的是一个参数列表跟apply一样,改变this指向后原函数会立即执行,且此方法只是临时改变this指向一次
- bind方法和call很相似,第一参数也是this的指向,后面传入的也是一个参数列表(但是这个参数列表可以分多次传入)改变this指向后不会立即执行,而是返回一个永久改变this指向的函数
使用区别
```javascript function func(){} const thisArg = {}
func.call(thisArg, param1, param2, …)
func.apply(thisArg, [param1,param2,…])
func.bind(thisArg, param1, param2, …)
<a name="SlVQq"></a>
### 手写简版call方法
```javascript
Function.prototype.yourCall = function(){
//获取需绑定的上下文
const target = Array.from(arguments).shift();
// 获取传入的参数
const args = Array.from(arguments).slice(1);
// 使用Symbol创建key,防止属性覆盖
const key = Symbol('key')
// 在上下文添加this 此处的this为调用yourCall的函数
target[key] = this;
// 简单理解谁调用函数 this则指向谁
target[key](...args)
delete target[key]
}
const fn = function(name,age,gender){
this.name = name;
this.age = age;
this.gender = gender;
}
const person = {}
fn.yourCall(person, "长青", 23, true)
console.log(person)
手写简版apply方法
思路与 call 方法一直,只是传参的方式不一样。
Function.prototype.yourApply = function(){
//获取需绑定的上下文
const target = Array.from(arguments).shift();
// 获取传入的参数
const args = Array.from(arguments)[1] || [];
// 使用Symbol创建key,防止属性覆盖
const key = Symbol('key')
// 在上下文添加this 此处的this为调用yourCall的函数
target[key] = this;
// 简单理解谁调用函数 this则指向谁
target[key](...args)
delete target[key]
}
const fn = function(name,age,gender){
this.name = name;
this.age = age;
this.gender = gender;
}
const person = {}
fn.yourApply(person,['长青',23, true])
console.log(person)
手写简版bind方法
思路和上面差不多,只不过call、apply在绑定this的同时执行了函数,bind在绑定this后返回了该函数
Function.prototype.yourBind = function () {
const target = Array.from(arguments).shift();
const args = Array.from(arguments).slice(1);
const key = Symbol('key');
target[key] = this;
return function () {
target[key](...args)
delete target[key]
}
}
function print() {
console.log(this)
}
const person = {name: '长青'}
const myPrint = print.yourBind(person)
myPrint()