-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Description
new 运算符:
运算符创建一个用户定义的对象类型的实例 或 具有构造函数的内置对象类型之一。
bind 函数:
方法会创建一个新函数,当这个新函数被调用时,bind()的第一个参数将作为它运行时的this,之后的一系列参数将会传递的实参前传入作为它的参数。
bind函数的特点:
- 改变this指向
- 第一个参数是this的值,后面的参数是函数接收的参数的值
- 返回值不变
// 手写bind
Function.prototype.myBind = function() {
// 为了获取原函数
const self = this;
// 执行slice方法,其中的this指向arguments,得到真正的数组
const args = Array.prototype.slice.call(arguments);
// 拿到第一个参数
const thisValue = args.shift();
return function() {
// 返回一个函数,它是一个匿名函数,整个匿名函数,就是保存在变量中的新的函数
// 返回新函数里执行原函数
return self.apply(thisValue, args);
}
}
new原理:
- 创建空对象,作为将要返回的对象实例
- 指向原型,将这个空对象的原型,指向构造函数的prototype属性
- 绑定this,将这个空对象赋值给函数内部的this关键字
- 返回新对象,开始执行构造函数内部的代码
// 手写new
function myNew(fn, ...args) {
// 定义个空对象
const obj = {};
// 隐式原型指向构造函数的显式原型
obj.__proto__ = fn.prototype;
// 执行构造函数,this指向空对象
fn.apply(obj, args);
// 返回对象
return obj;
}
// new,创建实例,构造函数,剩余参数
const createInstance = (Constructor, ...args) => {
// 创建对象,并指向构造函数的原型
const obj = Object.create(Constructor.prototype);
// 构造函数内部的 this 指向 instance 变量
let res = Constructor.call(obj, ...args);
// 判断 是否是 函数或对象
const isObj = res !== null && typeof res === 'object';
const isFunc = typeof res === 'function';
const isFunc || isObj ? res : obj;
}
// objectFactory
function objectFactory() {
var object = new Object();
var Constructor = Array.prototype.shift.call(arguments);
// 原型式继承
object.__proto__ = Constructor.prototype;
// arguments第一个已经被shift,此时arguments是我们想要的参数
var result = Constructor.apply(object, arguments);
return typeof result === 'object' ? result : object;
}
new的运行过程:
- 新建一个内部对象
- 给这个对象指定一个隐式原型链,对象的
__proto__
指向构造函数的prototype
- 指定对象的
this
- 执行构造函数内部的代码
- 如果有返回值,就返回构造函数的返回值,否则就返回新建的对象
function objectFactory() {
const constructor = [].shift.call(arguments)
// 新建一个对象,并且将对象的隐式原型指定为构造函数的显示原型
// 这样就能访问到构造函数的原型中的属性
let newObject = Object.create(constructor.prototype);
// apply将 this 指定为 newObject
let res = constructor.apply(newObject, arguments);
// 判断 构造函数 返回的值是否是对象
return typeof res === 'object' ? res : newObject
}
模拟手写new
// new
function create(Con, ...args) {
let obj = {}
// Object.getPrototypeOf(obj) 相当于obj.__proto__
Object.setProrotypeOf(obj, Con.prototype);
let result = Con.apply(obj, args)
return result instanceof Object ? result : obj
}
模拟手写bind
Function.prototype.myBind = function(context) {
if(typeof this !== 'function') {
throw new TypeError('Error');
}
var _this = this
var args = [...arguments].slice(1)
return function F() {
if (this instanceof F) {
// instanceof 返回true
return new _this(...args, ...arguments);
}
return _this.apply(content, [...args, ...arguments])
}
}
new关键字实现了什么
- this指向新创建的对象
- 对象的
[[prototype]]
属性指向构造函数的prototype - 执行函数,返回一个新对象
- 如果函数没有返回对象类型Object,那么new表达式中的函数调用会自动返回这个新的对象
function objectFactory(func) {
if(typeof func !== 'functio') {
throw new Error('请传入一个函数')
}
let obj = Object.create(func.prototype);
let args = [...arguments].slice(1);
const result = func.apply(obj, args);
let objectResult = typeof result === 'object' && result !== null;
let funcResult = typeof result === 'function';
return (objectResult || funcResult) ? result : obj;
}
bind实现了什么
- bind返回一个函数
- bind可以传入参数
- bindFunc返回的函数也可以传入参数
- this指向bindObjNew
Function.prototype.myBind = function(context) {
if(typeof this !== 'function') {
throw new Error('请输入一个函数');
}
let args = [...arguments].slice(1);
let _this = this;
let fBound = function() {
let args2 = [...arguments];
// return _this.apply(context, [...args, ...args2]);
return _this.apply(this instanceof fBound ? this : context, [..args, ...args2])
}
return fBound;
}
Bind函数实现:
- 返回一个函数
- 可以传入参数
Function.prototype.myBind = function(context) {
if(typeof this != 'function') {
throw new TypeError('error')
}
let _this = this
// 函数剩余的参数
let args = [...arguments].slice(1)
return function F() {
// 因为返回的是一个函数,所以可以 new F(),所以要进行判断
if(this instanceof F) {
return new _this(...args, ...arguments);
}
return _this.apply(context, args.concat(...arguments));
}
}
New 实现:
- 创建了一个新对象
- 链接到原型
- 绑定到this
- 返回新对象
function objectFactory() {
// 新创建一个对象
let obj = {}
// 取出构造函数
constructor = [].shift.call(arguments);
// 链接到原型
obj.__proto__ = constructor.prototype;
// 绑定到this
constructor.apply(obj, arguments);
// 返回新对象
return obj;
}
new 关键字做了什么?
- 一个新的对象
- 新对象的
__proto__
指向构造函数的prototype - 使用apply改变构造函数的this指向,使其指向新对象,这样一来obj就有构造函数里面的属性啦
- 判断构造函数是否有返回值,如果构造函数返回对象,则直接返回构造函数中的对象
- 返回新对象
function myNew() {
let obj = new Object();
let constrctor = Array.prototype.shift.call(arguments);
obj.__proto__ = constrctor.prototype;
let res = constrctor.apply(obj, arguments);
return typeof res === "object" ? res : obj;
}
bind:
Function.prototype.Mybind = function (context) {
if (typeof this !== "function") return "我们要函数才可以调用哦~";
let myFn = this;
// 当前调用传进来的参数
let arg = Array.prototype.slice.call(arguments, 1);
let fNOP = function () {};
let fBound = function () {
let bindArg = Array.prototype.slice.call(arguments);
// 当函数作为构造函数时,this会指向他的实例fbound
// 当函数作为普通函数的时候,this会指向window
return myFn.apply(
this instanceof fNOP ? this : context,
bindArg.concat(arg)
);
};
// 修改函数的原型指向this的原型 实例可以继承绑定函数的原型中的值,因为是引用类型~
fBound.prototype = this.prototype;
// 中转一下就不会修改到绑定函数的this啦
fBound.prototype = new fNOP();
return fBound;
};
new实践
Object.create = function(o) {
function f() {}
f.prototype = o
return new f;
}
function objectFactory() {
var obj = new Object(), // 从Object.prototype上克隆一个对象
Constructor = [].shift.call(arguments); // 取得外部传入的构造器
var F = function() {}
F.prototype = Constructor.prototype;
obj = new F(); // 指向正确的原型
var res = Constructor.apply(obj, arguments); // 借用外部传入的构造器给obj设置属性
return typeof res === 'object' ? res : obj; // 确保构造器总是返回一个对象
}
Function.prototype.myBind = function(context) {
if (typeof this !== 'function') {
throw new Error('Function.prototype.bind - what is trying to be bound is not callable');
}
var selft = this;
var args = Array.prototype.slice.call(arguments, 1);
var fNOP = function() {};
var fBound = function() {
var bindArgs = Array.prototype.slice.call(arguments);
return self.apply(this instanceof fNOP ? this : context, args.concat(bindArgs));
}
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
}
Metadata
Metadata
Assignees
Labels
No labels