为了账号安全,请及时绑定邮箱和手机立即绑定

JavaScript原型继承实质

原型继承机制的实质

如果想理解 JavaScript 的原型继承,首先就要彻底抛开传统面向对象语言( 如Java )的类继承。虽然同为面向对象的语言,但 JavaScript 拥有更加灵活的继承方式。

例子:

var humen = {
    name: "Tom"
}

var person = Object.create(humen);

console.log(person.name); //输出:Tom

例子中,person 本身并没有 name 属性,name 定义在 humen 中,我们通过使用 Object.create(humen) 方法,就让两个本来互不相干的对象,产生了某种关联。这种关联不是类和对象之间,而是两个对象的之间的关联:如果对象 person 本身没有某个属性,引擎就会去访问另一个对象 humen 的属性。那么,Object.create(humen) 是不是可以理解为,发生了下面的事情:

//伪代码
var obj={};
obj.__proto__=humen;

var person=obj;

除了使用 Object.create() 方法,我们也可以使用 Object.setPrototypeOf() 方法创建两个对象之间的关联:

例子:

var humen = {
    name: "Tom"
}

var person = {};

Object.setPrototypeOf(person, humen);

console.log(person.name); //输出:Tom

方法 Object.setPrototypeOf(person, humen) 执行时,可以理解为发生了下面的事情:

//伪代码
person.__proto__=humen;

通过上面的两个例子,我们好像明白了 JavaScript 原型继承机制的实质:那就是通过某些方法,把对象 humen 关联到对象 person 的 [[Prototype]] 上,当我们在对象 person 上没有找到需要的属性或者方法时,引擎就会继续在 [[Prototype]] 关联的对象 humen 上继续查找。

JavaScript 的" 构造函数 "

" 构造函数 “打上引号,是因为在 JavaScript 中并没有真正意义上的” 构造函数 "。原型查询机制中,我们提到过函数的两种身份,当函数作为第二种身份去调用时( 通过 new 关键字去调用 ),函数负责创建一个新对象并绑定 this 值,其实还有一个更重要的工作,那就是把函数 prototype 引用的对象关联到新对象的 [[Prototype]] 上。

例子:

function Fn() {
    this.name = "Tom";
};
Fn.prototype.age = 20;

var person = new Fn();

console.log(person.age); //输出:20

函数 new Fn() 执行时,可以理解为发生了下面的事情:

//伪代码
var obj = {};
obj.name = "Tom";
obj.__proto__ = Fn.prototype;

person = obj;

内置" 构造函数 "

由于函数在 JavaScript 中有了这样的一层身份,所以它的地位也变得举足轻重。针对不同的数据类型,JavaScript 内置了很多函数,这些内置函数从表现形式来说很像 Java 中的类。当使用 new 关键字去调用这些内置函数的时候,就完成了内置函数 prototype 引用的对象关联到新对象的 [[Prototype]] 上的工作,从而完成了继承。

例子:

//JavaScript 中常见的内置函数
var o = Object.prototype.toString;
console.log(o.call(String)); //输出:[object Function]
console.log(o.call(Number)); //输出:[object Function]
console.log(o.call(Boolean)); //输出:[object Function]
console.log(o.call(Array)); //输出:[object Function]
console.log(o.call(Object)); //输出:[object Function]
console.log(o.call(Function)); //输出:[object Function]
console.log(o.call(Date)); //输出:[object Function]
console.log(o.call(RegExp)); //输出:[object Function]
console.log(o.call(Error)); //输出:[object Function]

//调用内置函数,创建实例对象
var a = new Array();

实例对象 a 默认继承的属性和方法的部分截图:

图片描述

判断对象与对象的" 继承 "关系

isPrototypeOf() 方法

该方法用于检查实例对象的整条原型链中是否出现过某个原型对象。

例子:

var humen = {
    name: "Tom",
    age: 20
}

var person = {};
Object.setPrototypeOf(person, humen);

console.log(humen.isPrototypeOf(person)); //输出:true
console.log(Object.prototype.isPrototypeOf(person)); //输出:true

instanceof 操作符

instanceof 是 java 中的一个运算符,用于确定一个对象是否为一个类的实例,instanceof 的左侧是一个普通的对象,右侧是一个类名,在 JavaScript 中,右侧是一个函数名。我们知道,JavaScript 原型继承的实质是两个对象之间的关联,并非类与对象之间的关系,因此,在 JavaScript 中使用 instanceof 操作符有其不合理性。

例子:

function Humen() {
    this.name = "Tom";
    this.age = 20;
}
var person = new Humen();

console.log(person instanceof Humen); //输出:true
console.log(person instanceof Object); //输出:true

运行时流程图

结合以上内容,JavaScript 的运行时流程图如下:
图片描述

这张图会根据内容的增加不断进行补充。


深入挖掘系列手记

浏览器理论(未更新)


如有错误,欢迎指正,本人不胜感激。

点击查看更多内容
2人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消