@1 首先我们先了解下原型链的基础知识。
function Fn(x,y) {this.x=x; this.y =y; this.say=()=>{console.log(this.x)}}
let res = Fn(10,20) // 普通函数执行 因为函数体内部没有返回值所以普通函数执行得不到返回
的结果。
let f1 = new Fn(10,20) // 这是构造函数执行
let f2 = new Fn(10,20) // 这是创造另外一个类的实例对象
console.log(f1.sum) // 因为不存在所以结果是undefiend
console.log(f1.say) // 得到的结果是10
console.log(f1.say===f2.say) // false 创建的两个实例对象是不相同的
@2 普通函数与构造函数的区别;
构造函数执行也像普通函数执行一样产生私有的上下文(作用域 初始this 代码执行)
构造函数在执行的时候会创建出一个空实例对象, 让上下文中的this执行创建的实例对象,观
察函数的返回值,如果返回值的原始值类型或者没有返回值则把创建的实例对象返回,只有
自己手动返回对象类型值,才以自己返回的为主。
@3 构造函数的特点:
1. 构造函数原型对象中有一个constructor(构造器)返回值是当前构造函数本身
Fn.prototype.constructor === Fn;
2. 不具备prototype的函数, 箭头函数
3. 每一个对象数据类型的值都具备一个属性 __proto__, 属性值 指向自己所属原型Prototype
4. 对象数据类型值、普通对象 特殊对象:数组 正则 日期 Math Error,函数对象,以及构造函
数的prototype也属于对象数据类型。
@4 案例展示:
function Fn(){
this.x = 100
this.y = 200
this.getX = function (){ console.log(this.x)}
}
Fn.prototype.getX= function (){console.log(this.x)}
Fn.prototype.getY = function(){console.log(this.Y)}
let f1 = new Fn;
let f2 = new Fn;
console.log(f1.getX===f2.getX) // false 每次new创建的实例对象是互不相关的
console.log(f1.getY===f2.getY)// true 两个实例对象自身都没有getY这个方法找的都是原型的
console.log(f1.__proto__.getY===fn.prototype.getY)// true f1.__proto__等于Fn.prototype
console.log(f1.__proto__.getX===f2.getX) // false F1找的是原型上面的方法f2找的是自身的
console.log(f1.getX===Fn.prototype.getX)// false 自身与原型的方法不相等
console.log(f1.constoructor) //Fn 相当于f1.__proto__.constructor
console.log(Fn.prototype.__proto__.constorctor)// Object 相当于object.prototype.constructor
f1.getX() // 100
f1.__proto__.getX() // undefiend Fn.prototype的this执行Fn.prototype 但这个this上面没有x
f2.getY() // 200
Fn.prototype.getY() // undefiend Fn.prototype的this指向Fn.prototype 但这个this上面没有y
@ 5 原型链之间的关系:
1 每一个构造函数function Fn(){} 通过new都可以得到一个实例对象f1 = new Fn();
2 每个实例对象的__proto__都指向其构造函数的prototype 也就是f1.__proto__ ===
Fn.prototype;
3 每一个构造函数的prototype本身也是一个对象数据类型,也有__proto__属性,所以指向更
高一级的Object.prototype;
4 Object.prototype也是属于对象数据类型也有__proto__属性,但是object.prototype的
__peoto__指向了null。
@ 6 封装new实例对象的函数:
function _new(ctor,...params) {
let obj1 = {} // 创建一个空的对象
obj1.__proto__ = ctor.prototype // 让对象的__proto__属性指向于构造函数的prototype
const result = ctor.call(obj1,...params) // 改变this指向
if(result !== null && /^(object | function)$/.test(typeof result)) return result; // 如果这个
函数返回的是原始值类型 则把实例返回
return obj;
}
let sammao = _new(Dog,'三毛');
严格判断:
function _new(ctor,...params) {
let obj1 = {} // 创建一个空的对象
if(!ctor.prototype || ctor===Symbol || ctor===BigInt) throw new Error(...) // 抛出错误
obj = Object.create(ctor.prototype) // 把ctor的原型挂载在obj原型上面
obj1.__proto__ = ctor.prototype // 让对象的__proto__属性指向于构造函数的prototype
const result = ctor.call(obj1,...params) // 改变this指向
if(result !== null && /^(object | function)$/.test(typeof result)) return result; // 如果这个
函数返回的是原始值类型 则把实例返回
return obj;
}