原型与原型链
原型对象
构造函数可以通过new的方法来创建一个实例,而每一个构造函数都有一个prototype的属性指向一个原型对象。原型对象中所有的属性与方法都可以被该函数所创建的实例所共享。
原型链
每个被构造函数创建出来的实例都有一个隐式的属性__proto__,该属性指向构造函数的prototype,即原型对象。浏览器在取对象中的方法时,会先在对象中寻找是否存在该方法,如果没有则通过__proto__到其原型对象上寻找,以此一层层通过__proto__,直至为null。
原型链是基于proto形成的,继承是通过prototype实现的
Object,Function,__proto__,prototype
在JS中,万物皆对象,所以函数(方法)也是一个对象。
所有的对象都有一个根源 Object.prototype,Object.prototype只是一个普通对象
根源的原型对象是null
但是null却不是一个对象,虽然用typeof验证null为object,这个是JS的bug。
(typeof Object.prototype) === object;//true
Object.prototype.__proto__=== null;//true
Object.prototype.prototype === undefied;//true
特例:__Object和Function既是对象,又是函数,两者内部同时含有proto和prototype属性,他们关系较为复杂__Function.prototype指向“__内置函数__”,而Object.prototype指向“__根源对象__”
Object.__proto__ === Function.prototype //true
Object.__proto__ === Function.__proto__//true
Object.prototype === Function.prototype.__proto__ // true
//因此
Function instanceof Object //true
Object instanceof Function //true
x instanceof y,当y的原型对象在x的原型链之上,返回true,否则返回false
构造函数与普通函数
创建方式相同
构造函数也是个普通函数,但是一般来说,构造函数会采用首字母大写的方式。
调用方式不同,目的不同
普通函数: 直接调用,返回值为函数调用的之后return的值,无return则为空;
构造函数:需要用new调用,以创建实例的方式来调用,目的是创建一个指向构造函数的原型的一个实例对象。
构造函数调用创建实例的时候内含多步骤
这个问题可以换个角度说,就是当我们再new一个对象的时候,内部发生了什么。
1、首先需要创建一个空对象。
2、将空对象的__proto__指向构造函数的prototype(构造函数的原型对象),以此获得原型的方法与属性
3、绑定this的指向
4、返回新对象
在文章下方会手动实现一个简易版的new方法
构造函数用this构造内部方法与属性
function Cat(name, age) {
this.age = age
this.name = name
this.run = run
function run() {
}
}
let cat = new Cat('米粒', '6个月')
构造函数所创建的实例都可以用instanceof
可以用来验证该实例是否由验证的构造函数所创建的。原理就是去查找实例的__proto__是否与构造函数的prototype所指向的原型对象是同一个。
文章下方将会手写一个简略版的instanceof
手写new
当我们再new一个对象的时候,内部发生了什么。
1、首先需要创建一个空对象。
2、将空对象的__proto__指向构造函数的prototype(构造函数的原型对象),以此获得原型的方法与属性
3、绑定this的指向
4、返回新对象
function Cat(name, age) {
this.age = age
this.name = name
this.run = run
function run() {
}
}
function _new() {
//
let newObject = new Object()
// arguments是传入函数的参数,因为是类数组的形式,无法直接使用shift方法
// 所以使用ES6的新特性进行转换
// Array.prototype.shift.apply(arguments)用数组原生方法也是可以的
arguments = Array.from(arguments)
// 取出构造函数
let Constructor = arguments.shift()
// 获得构造函数的原型对象上的方法与属性
newObject.__proto__ = Constructor.prototype
// 绑定this的指向
Constructor.apply(newObject, arguments)
return newObject
}
cat = _new(Cat, '米粒', '6个月')
console.log(cat)
// Cat { age: '6个月', name: '米粒', run: [Function: run] }
手写instanceof
原理:查找实例的__proto__是否与构造函数的prototype所指向的原型对象是同一个。
function instance_of(L, R) {
const R_prototype = R.prototype
let L_proto = L.__proto__
let flage = false
while(L_proto !== null) {
if (L_proto === R_prototype) {
flage = true
break
}
L_proto = L_proto.__proto__;
}
return flage
}
// 使用上方的_new方法来创建实例
cat = _new(Cat, '米粒', '6个月')
console.log(cat)
console.log(cat instanceof Cat) // true
console.log(instance_of(cat, Cat)) // true
console.log(instance_of(cat, Object)) // true
console.log(instance_of(cat, {})) // false
console.log(instance_of(cat, Boolean)) // false
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。