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 的运行时流程图如下:
这张图会根据内容的增加不断进行补充。
深入挖掘系列手记
浏览器理论(未更新)
如有错误,欢迎指正,本人不胜感激。
共同学习,写下你的评论
评论加载中...
作者其他优质文章