对于新人来说,JavaScript的原型是一个很让人头疼的事情,一来prototype容易与__proto__混淆,二来它们之间的各种指向实在有些复杂,其实市面上已经有非常多的文章在尝试说清楚,有一张所谓很经典的图,上面画了各种线条,一会连接这个一会连接那个,说实话我自己看得就非常头晕,更谈不上完全理解了。所以我自己也想尝试一下,看看能不能把原型中的重要知识点拆分出来,用最简单的图表形式说清楚。
我们知道原型是一个对象,其他对象可以通过它实现属性继承。但是尼玛除了prototype,又有一个__proto__是用来干嘛的?长那么像,让人怎么区分呢?它们都指向谁,那么混乱怎么记啊?原型链又是什么鬼?相信不少初学者甚至有一定经验的老鸟都不一定能完全说清楚,下面用三张简单的图,配合一些示例代码来理解一下。
增加原型链上的方法实例
var _self = new EditView();
$(function () {
;(function($){
var options = {
fieldCode: "gfyId",
url: "../../Security/selector/user/PublicServiceUserList.html?s=" + Math.random(),
multi: false,
code: "gfyId,gfyIdName",
keyRespField: "gfyId,id",
dictCode: "publicserviceName",
area: ['90%','90%']
};
/*引用查询选择*/
function renderSelectorMy(options){
debugger;
var defaults = {};
this.settings = $.extend({},defaults,options);
var $domObj = $("#" + this.settings.fieldCode + "-popSelector");
this.settings.url = $domObj.attr("action") ? $domObj.attr("action") : this.settings.url;
this.settings.multi = $domObj.attr("multi") ? $domObj.attr("multi") : this.settings.multi;
this.settings.code = $domObj.attr("codeAndName") ? $domObj.attr("codeAndName").split(",") : this.settings.code.split(",");
this.settings.keyRespField = this.settings.keyRespField ? this.settings.keyRespField.split(",") : "";
this.init();
}
//为函数添加原型链上的方法
renderSelectorMy.prototype = {
init: function(){
debugger;
var _self = this,
_keys = _self.settings.code;
$("input[name='" + _keys[0] +"']").parent().parent().find("button").unbind('click').bind('click', function(){
var action = "_self." + $(this).attr("action");
eval(action);
});
},
querySelect : function(thi,event){
debugger;
var _self = this;
var url = _self.settings.url;
var _keys = _self.settings.code;
var keyRespField = _self.settings.keyRespField;
var id = keyRespField[1];
var ids = $("input[name='" + _keys[0] +"']").val();
if(url.indexOf("?") != -1) {
url = url + "&" + id + "="+ids;
}else {
url = url + "?" + id + "="+ids;
}
$Core.UI.openDialog("selwind", url,
{
title: "列表选择",
width: _self.settings.area[0],
height: _self.settings.area[1],
onClose: function () {
}
});
},
echoSelect : function(_data){
var _self = this;
var data = _data.data,
_keys = _self.settings.code,
_rkeys = _self.settings.keyRespField,
dictName = "",
dictCode = _self.settings.dictCode;
$Core.DicCache.initDictionary(dictCode,function(dicts){
var _dicts = dicts;
if(dicts && dicts.data){
var dictDatas = dicts.data[dictCode];
for(var i=0,len=dictDatas.length; i<len; i++){
var item = dictDatas[i];
if(data[_keys[0]] == item[_rkeys[1]]){
var itemName = item.text;
dictName += itemName +",";
}
}
$("span input:text", $("div #" + _keys[0] + "-popSelector")).val(dictName.substr(0,dictName.length-1));
}else{
$("span input:text", $("div #" + _keys[0] + "-popSelector")).val(dictName);
}
})
},
selectResultAfterCallback: function(checkRlt){
var _self = this,
multi = _self.settings.multi;
if(checkRlt.length == 0){
$Core.UI.message.warning("选请选择数据!");
}
if(!multi && checkRlt.length != 1){
$Core.UI.message.warning("单选,请选择一条数据!");
}
var _keys = _self.settings.code,
code = "",
name = "";
if(!_self.settings.multi){
code = checkRlt[0]['code'];
name = checkRlt[0]['name'];
}else{
var _code = "",
_name = "";
for(var i=0,len=dataArr.length; i<len; i++){
_code += checkRlt[i]['code'] +",";
_name += checkRlt[i]['name'] +",";
}
code = _code.substring(0,_code.length-1);
name = _name.substring(0,_name.length-1);
}
//给input[name='']:text 赋值
$("input[name='" + _keys[0] + "']:hidden").val(code);
$("span input:text", $("div #" + _keys[0] + "-popSelector")).val(name);
$(".panel-tool-close").trigger('click');
}
}
//扩展jquery类方法
$.extend({
renderSelectorMyf : function(options){
return new renderSelectorMy(options);
}
});
})(jQuery)
renderSelector = $.renderSelectorMyf({
fieldCode: "gfyId",
url: "../../Security/selector/user/PublicServiceUserList.html?s=" + Math.random(),
multi: false,
code: "gfyId,gfyIdName",
keyRespField: "gfyId,id",
dictCode: "publicserviceName",
area: ['90%','90%']
});
_self.renderSelectors = [renderSelector];
});
var EditView = function(){
_this = this;
if(type != "add" && _this.renderSelectors){
for(var i=0,len=_this.renderSelectors.length; i<len; i++){
var renderSelector = _this.renderSelectors[i],
dictDatas = $Core.DicCache.get(renderSelector.settings.dictCode);
renderSelector.echoSelect(data, dictDatas);
}
}
}
$("#btnConfirm").bind('click',function(){
var $dg = $("#dglist");
var rows = $dg.datagrid("getSelections");
var renderSelectObj = parent.renderSelector;
var _datas = [];
for(var i=0,len=rows.length; i<len; i++){
var dataItem = {};
dataItem.code = rows[i].id;
dataItem.name = rows[i].userName;
dataItem.address = rows[i].address;
_datas.push(dataItem);
}
renderSelectObj.selectResultAfterCallback(_datas);
});
JS 面向对象之原型链
对象的原型链
- 只要是对象就有原型
- 原型也是对象
- 只要是对象就有原型, 并且原型也是对象, 因此只要定义了一个对象, 那么就可以找到他的原型, 如此反复, 就可以构成一个对象的序列, 这个结构就被成为原型链
- 原型链到哪里是一个头?
- 一个默认的原型链结构是什么样子的?
- 原型链结构对已知语法结构有什么修正?
原型链的结构
- 原型链继承就是利用就是修改原型链结构( 增加、删除、修改节点中的成员 ), 从而让实例对象可以使用整个原型链中的所有成员( 属性和方法 )
- 使用原型链继承必须满足属性搜索原则
属性搜索原则
- 所谓的属性搜索原则, 就是对象在访问属性与方法的时候, 首先在当前对象中查找
- 如果当前对象中存储在属性或方法, 停止查找, 直接使用该属性与方法
- 如果对象没有改成员, 那么再其原型对象中查找
- 如果原型对象含有该成员, 那么停止查找, 直接使用
- 如果原型还没有, 就到原型的原型中查找
- 如此往复, 直到直到 Object.prototype 还没有, 那么就返回 undefind.
- 如果是调用方法就包错, 该 xxxx 不是一个函数
原型链结构图
-
构造函数 对象原型链结构图
function Person (){}; var p = new Person();
{} 对象原型链结构图
[] 数组原型链结构图
Object.prototype
对应的构造函数
- div 对应的构造函数
-
div -> DivTag.prototype( 就是 o ) -> Object.prototype -> null
var o = {
appendTo: function ( dom ) {
}
};
function DivTag() {}
DivTag.prototype = o;
var div = new DivTag();
函数的构造函数 Function
在 js 中 使用 Function 可以实例化函数对象. 也就是说在 js 中函数与普通对象一样, 也是一个对象类型( 非常特殊 )
- 函数是对象, 就可以使用对象的动态特性
- 函数是对象, 就有构造函数创建函数
- 函数是函数, 可以创建其他对象(函数的构造函数也是函数)
- 函数是唯一可以限定变量作用域的结构