SAP UI5框架Component.js里extend函数的实现原理
For every Fiori application we have Component.js, and there is a function extend() call. See one example below.
What is the purpose of this function call and what functionality would it achieve?
In order to understand the logic of extend, it is necessary to understand prototype concept in JavaScript. Let’s have a look at some more simple example.
See this simple html source code:
<html>
<script>
function Animal(name) {
this.sName = name;
console.log("constructor in Animal");
}
Animal.prototype.speak = function() {
console.log("My name is " + this.sName);
};
function Cat(name) {
Animal.call(this, name);
console.log("constructor in cat");
}
Cat.prototype = new Animal();
var animal = new Animal("Jerry");
animal.speak();
var cat = new Cat('Tom');
cat.speak();
console.log("cat is animal?" + ( cat instanceof Animal ));
console.log("cat is Cat?" + ( cat instanceof Cat ));
console.log(cat.constructor);
</script>
</html>
I use prototype inheritance to achieve the class inheritance logic which is commonly used in other language like Java.
cat instanceof Animal and cat instanceof Cat both return true as expected.
There are two flaws of this inheritance solution:
(1) every variable created by function constructor has one attribute proto, which points to the prototype object of its constructor. This could be verified by the fact that statement “cat.proto === Cat.prototype ” returns true.
In this example, you can find there are actually duplicate attribute sName, one in cat itself and the other one in its prototype.
(2) in above code line 17, I try to build the inheritance relationship from Animal to Cat. Here a new instance of Animal is created. Suppose in productive code if we have a complex implementation of Animal, this initialization could consume unnecessary resource and memory to finish.
So another approach is used:
<html>
<script>
Function.prototype.extend = function(parent) {
function dummy() {};
dummy.prototype = parent.prototype;
this.prototype = new dummy();
this.prototype.constructor = this;
}
function Animal(name) {
this.sName = name;
console.log("constructor in Animal");
}
Animal.prototype.speak = function() {
console.log("My name is " + this.sName);
};
function Cat(name) {
Animal.call(this, name);
};
Cat.extend(Animal);
var cat = new Cat("Jerry");
cat.speak();
console.log("cat is Cat?" + (cat instanceof Cat));
console.log("cat is Animal?" + (cat instanceof Animal));
console.log(cat.constructor);
</script>
</html>
Both flaws in first approach are avoided:
(1) No duplicate attribute “sName” in prototype chain now.
(2) The initialization of a new instance of Animal when trying to build prototype chain is avoided. Instead here I use a very light weighted, dummy function as a bridge to connect Animal and Cat. The trick is done among lines 5 ~ 8 below. Once done, every variable created by constructor Cat has its proto points to Animal.
Now we have already enough knowledge to understand the extend() call done in Componnet.js in Fiori application.
(1) extend call will call Metadata.createClass.
(2) In Metadata.createClass, the essential idea of line 333 is just exactly the same as the code in my second prototype inheritance approach:
function dummy() {};
dummy.prototype = parent.prototype;
this.prototype = new dummy();
a. within jQuery.sap.newObject, a dummy object will be created:
b. here the argument oPrototype is the prototype of sap.ca.scfld.md.ComponentBase:
Once prototype chain is built, the function call jQuery.sap.setObject is called to expose cus.crm.opportunity.Component as a global JavaScript object:
Finally these below are what we have got:
(1) we can directly access cus.crm.opportunity.Component in JavaScript code or console thanks to jQuery.sap.setObject call.
(2) The prototype chain from sap.ca.scfld.md.ComponentBase to cus.crm.opportunity.Component is built, which could be confirmed by the picture below:
Now when I enter the context of my application, I can get the instance of this component via this(controller reference).getOwnerComponent().
From the belowing two test statement in console, I can ensure that the prototype chain is built:
(1) ownComponent.proto.proto.constructor === sap.ca.scfld.md.ComponentBase returns true
(2) ownComponent.hasOwnProperty(“getMetadata”) returns false and ownComponent.proto.proto.hasOwnProperty(“getMetadata”) returns true.
from returned metadata, we can find all the metadata information defined in the application and passed from extend call:
要获取更多Jerry的原创文章,请关注公众号"汪子熙":
相关文章
- Fabric.js 使用纯色遮挡画布(前景色)
- 想比较全面地学习 SAP XXX,能指导下从哪儿开始学习吗?
- SAP UI5 sap.ui.Device.media 公有方法介绍
- SAP Java Connector 错误 - JCO_ERROR_COMMUNICATION
- js 数组去除重复数据-5 个提升你 JS 编码水平的实例
- 【JS 逆向百例】猿人学系列 web 比赛第五题:js 混淆 - 乱码增强,详细剖析
- 如何使用jscythe并通过Node.js的Inspector机制执行任意JS代码
- 如何用 SAP Commerce Cloud CMS API 批量返回多个 CMS Component 数据
- 【源码】PDF.js批注注释插件库(纯JS). 创建和保存PDF批注(PDF 高亮/签名/插图/截屏/文本框/画笔/多边形)-pdf.js
- JS动态引入js、CSS动态创建script/link/style标签详解编程语言
- SAP RFC详解编程语言
- SAP基础:定位点运算详解编程语言
- SAP S/4 HANA新变化-主数据:物料主数据详解编程语言
- SAP批量锁定用户详解编程语言
- ABAP写数据到SAP服务器文件并读取详解编程语言
- 俄政府要求苹果与SAP开放源代码 以防外国监控
- 不靠谱企业的IT现状能糟糕到什么程度,气坏新来的SAP工程师
- 使用JS实现Redis数据读取(js读取redis)
- 数据JS技术实现实时获取Oracle数据(js实时获取oracle)
- JS在Oracle中的应用(js如何oracle)
- JavaScript探索之旅掌握Oracle和JS的完美融合(js与oracle)
- OracleSAP云融合突破IT发展新边界(oracle sap 云)
- JS将所有对象s的属性复制给对象r(原生js+jquery)
- js获取当前地址JS获取当前URL的示例代码