JavaScript 是动态的,本身不提供一个 class 的实现。即便是在 ES2015/ES6 中引入了 class 关键字,但那也只是语法糖,JavaScript 仍然是基于原型的。
当谈到继承时,JavaScript 只有一种结构:对象。每个实例对象(object)都有一个私有属性(称之为 proto )指向它的构造函数的
原型链:在 JavaScript 中,每个对象中都有一个 proto 属性,这个属性指向了当前对象的构造函数的原型。对象可以通过自身的 __proto__属性与它的构造函数的原型对象连接起来,而因为它的原型对象也有 __proto__,因此这样就串联形成一个链式结构,也就是我们称为的原型链。
原型对象(prototype):该原型对象也有一个自己的原型对象(__proto__),层层向上直到一个对象的原型对象为 null。根据定义,null 没有原型,并作为这个原型链中的最后一个环节。基于构造函数创建出来的实例, 都可以共享访问原型对象的属性。例如我们的 hasOwnProperty, toString ⽅法等其实是 Obejct 原型对象的方法,它可以被任何对象当做⾃⼰的⽅法来使⽤。hasOwnProperty 用于判断, 某个属性, 是不是自己的 (还是原型链上的) ,几乎所有 JavaScript 中的对象都是位于原型链顶端的 Object 的实例。
继承属性:JavaScript 对象是动态的属性“包”(指其自己的属性)。JavaScript 对象有一个指向一个原型对象的链。当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。
instanceof的原理
instanceof 运算符用于检测构造函数的 prototype 属性( constructor.prototype )是否出现在某个实例对象的原型链上。
new的实现
1.先创建一个新对象
2.使新对象的proto指向构造函数的prototype
3.改变新对象的this指向
4.构造函数中若返回值为object类型,则作为new方法的返回值返回,否则返回上述全新对象
function myNew(constructor,...args){
let obj={};
obj.__proto__=constructor.prototype;
let res=constructor.apply(obj,args);
return typeof res==='object'?res:obj;
}
apply,call和bind
的作用,实现方式
作用:call(),apply()和bind()都是用于改变this指向的。call()方法的作用和 apply() 方法类似,区别就是call()方法接受的是参数列表,而apply()方法接受的是一个参数数组。bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。call()和apply()调用后会立即执行函数,bind()不会执行函数。
call的实现
Function.prototype.myCall = function (context) {
context = context ? Object(context) : window
context.fn = this
let args = [...arguments].slice(1)
let r = context.fn(...args)
delete context.fn
return r
}
apply的实现
Function.prototype.myApply = function (context) {
context = context ? Object(context) : window
context.fn = this
let args = [...arguments][1]
if (!args) {
return context.fn()
}
let r = context.fn(...args)
delete context.fn;
return r
}
bind的实现
Function.prototype.Mybind = function (context) {
let _me = this
return function () {
return _me.apply(context)
}
}