ca88亚洲城唯一官方网站:浅谈javascript的原型继承,平台支持等详细介绍

第一种算是比较常见了,通过闭包Store
Value从而实现accessor,适用于所有浏览器.

来自John Resig早年的文章,大致翻译了一下,以作备忘。
令人高兴的是,我想我终于可以说,“现在,JavaScript的Getters和Setters使用非常广泛,它和每个JavaScript开发者的切身利益息息相关”。靠,我为了说这句话已经等了很久了。
首先,我们先来快速了解什么是Getters和Setters,以及它们为什么很有用。然后,我们来看看现在都有哪些平台支持Gettets和Setters。
Getters和Setters
Getters和Setters使你可以快速获取或设置一个对象的数据。一般来说,一个对象拥有两个方法,分别用于获取和设置某个值,比如:

请看源码:

复制代码 代码如下:

复制代码 代码如下:

复制代码 代码如下:

function Sandy(val){
var value = val;
this.getValue = function(){
return value;
};
this.setValue = function(val){
value = val;
};
}
//usage
var sandy = new Sandy(“test”);
sandy.value
// => undefined
sandy.setValue(“test2”)
sandy.getValue

{
getValue: function(){
return this._value;
},
setValue: function(val){
this._value = val;
}
}

function clone(o) {
var F = function(){};
F.prototype = o;
return new F();
}

下面是JavaScript权威指南(中文第五版)中P152页使用闭包的一个例子.

用这种方式写JavaScript的一个明显的好处是:你可以用它来隐藏那些不想让外界直接访问的属性。最终的代码看起来就像下面这样(用闭包保存新创建的Filed对象的value):

首先看ext(4.1的1896行开始)的原型式继承。

复制代码 代码如下:

复制代码 代码如下:

复制代码 代码如下:

function makeProperty(o, name, predicate) {
var value; //This is property value;

function Field(val){
var value = val;
this.getValue = function(){
return value;
};
this.setValue = function(val){
value = val;
};
}

var TemplateClass = function(){};
var ExtObject = Ext.Object = {
chain: function (object) {
TemplateClass.prototype = object;
var result = new TemplateClass();
TemplateClass.prototype = null;
return result;
}
}

//The setter method simply returns the value
o[‘get’ + name] = function() { return value;};

于是我们可以这样使用:

这里清除了object的prototype。
再看一下jquery是怎么玩的继承。

//The getter method stores the value or throws an exception if
//the predicate rejects the value
o[‘set’ + name] = function(v) {
if (predicate && !predicate(v) {
throw ‘set’ + name + ‘: invalid value ‘ + v;
} else {
value = y;
}
}
}

复制代码 代码如下:

复制代码 代码如下:

//The following code demenstrates the makeProperty() method
var o = {}; // Here is an empty object

var field = new Field(“test”);
field.value
// => undefined
field.setValue(“test2”)
field.getValue()
// => “test2”

var jQuery = function( selector, context ) {
return new jQuery.fn.init( selector, context, rootjQuery );

//Add property accessor methods getName and setName
//Ensure that only string values are allowed
makeProperty(o, ‘Name’, function(x) { return typeof x == ‘string’; });

我们来模拟上例中的 “隐藏的value属性”,我们的代码就像这样:

};

jQuery.fn = jQuery.prototype = {
constructor: jQuery,

o.setName(‘Frank’);   //Set the property value;
print(o.getName());   //Get the property value
o.setName(0); //Try to set a value of the wrong type

复制代码 代码如下:

init: function( selector, context, rootjQuery ) {

}

第二种方法是使用__defineSetter__与__defineGetter__来实现accessor,看下划线就知道它们并非标准,适用于Firefox
2.0+, Safari 3.0+, Google Chrome 1.0+ 和 Opera 9.5+
,方法使用见MDN.

function Field(val){
var value = val;
this.__defineGetter__(“value”, function(){
return value;
});
this.__defineSetter__(“value”, function(val){
value = val;
});
}

}

jQuery.fn.init.prototype = jQuery.fn;

jquery玩的就比较高,借助jQuery.fn.init来完成,但是思路一样。
司徒正美的mass里也有类似的继承,在lang_fix.js里面第17行:

复制代码 代码如下:

create: function(o){
ca88亚洲城唯一官方网站,if (arguments.length > 1) {
$.log(” Object.create implementation only accepts the first
parameter.”)
}
function F() {}
F.prototype = o;
return new F();
}

查看了一下es5的官方,找到了他的兼容补丁:

复制代码 代码如下:

// ES5 15.2.3.5
//
if (!Object.create) {
Object.create = function create(prototype, properties) {
var object;
if (prototype === null) {
object = { “__proto__”: null };
} else {
if (typeof prototype != “object”) {
throw new TypeError(“typeof prototype[“+(typeof prototype)+”] !=
‘object'”);
}
var Type = function () {};
Type.prototype = prototype;
object = new Type();
// IE has no built-in implementation of `Object.getPrototypeOf`
// neither `__proto__`, but this manually setting
`__proto__` will
// guarantee that `Object.getPrototypeOf` will work as expected with
// objects created using `Object.create`
object.__proto__ = prototype;
}
if (properties !== void 0) {
Object.defineProperties(object, properties);
}
return object;
};
}

上面的代码考虑的就比较全面,但是需要另外引入Object.defineProperties的补丁才行,源码相对就比较多了。

复制代码 代码如下:

// ES5 15.2.3.6
//
// Patch for WebKit and IE8 standard mode
// Designed by hax <hax.github.com>
// related issue:

// IE8 Reference:
//
//
// WebKit Bugs:
//
function doesDefinePropertyWork(object) {
try {
Object.defineProperty(object, “sentinel”, {});
return “sentinel” in object;
} catch (exception) {
// returns falsy
}
}
// check whether defineProperty works if it’s given. Otherwise,
// shim partially.
if (Object.defineProperty) {
var definePropertyWorksOnObject = doesDefinePropertyWork({});
var definePropertyWorksOnDom = typeof document == “undefined” ||
doesDefinePropertyWork(document.createElement(“div”));
if (!definePropertyWorksOnObject || !definePropertyWorksOnDom) {
var definePropertyFallback = Object.defineProperty;
}
}
if (!Object.defineProperty || definePropertyFallback) {
var ERR_NON_OBJECT_DESCRIPTOR = “Property description must be an
object: “;
var ERR_NON_OBJECT_TARGET = “Object.defineProperty called on
non-object: “
var ERR_ACCESSORS_NOT_SUPPORTED = “getters & setters can not be
defined ” +
“on this javascript engine”;
Object.defineProperty = function defineProperty(object, property,
descriptor) {
if ((typeof object != “object” && typeof object != “function”) || object
=== null) {
throw new TypeError(ERR_NON_OBJECT_TARGET + object);
}
if ((typeof descriptor != “object” && typeof descriptor != “function”)
|| descriptor === null) {
throw new TypeError(ERR_NON_OBJECT_DESCRIPTOR + descriptor);
}
// make a valiant attempt to use the real defineProperty
// for I8’s DOM elements.
if (definePropertyFallback) {
try {
return definePropertyFallback.call(Object, object, property,
descriptor);
} catch (exception) {
// try the shim if the real one doesn’t work
}
}
// If it’s a data property.
if (owns(descriptor, “value”)) {
// fail silently if “writable”, “enumerable”, or “configurable”
// are requested but not supported
/*
// alternate approach:
if ( // can’t implement these features; allow false but not true
!(owns(descriptor, “writable”) ? descriptor.writable : true) ||
!(owns(descriptor, “enumerable”) ? descriptor.enumerable : true) ||
!(owns(descriptor, “configurable”) ? descriptor.configurable : true)
)
throw new RangeError(
“This implementation of Object.defineProperty does not ” +
“support configurable, enumerable, or writable.”
);
*/
if (supportsAccessors && (lookupGetter(object, property) ||
lookupSetter(object, property)))
{
// As accessors are supported only on engines implementing
// `__proto__` we can safely override `__proto__` while
defining
// a property to make sure that we don’t hit an inherited
// accessor.
var prototype = object.__proto__;
object.__proto__ = prototypeOfObject;
// Deleting a property anyway since getter / setter may be
// defined on object itself.
delete object[property];
object[property] = descriptor.value;
// Setting original `__proto__` back now.
object.__proto__ = prototype;
} else {
object[property] = descriptor.value;
}
} else {
if (!supportsAccessors) {
throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED);
}
// If we got that far then getters and setters can be defined !!
if (owns(descriptor, “get”)) {
defineGetter(object, property, descriptor.get);
}
if (owns(descriptor, “set”)) {
defineSetter(object, property, descriptor.set);
}
}
return object;
};
}
// ES5 15.2.3.7
//
if (!Object.defineProperties) {
Object.defineProperties = function defineProperties(object, properties)
{
for (var property in properties) {
if (owns(properties, property) && property != “__proto__”) {
Object.defineProperty(object, property, properties[property]);
}
}
return object;
};
}

EcmaScript6的类继承。

复制代码 代码如下:

class module extends Base {
constructor() {
}
}

越玩越像java了,不过es6很多浏览器还不支持。
最后推荐的写法:

复制代码 代码如下:

if (!Object.create) {
Object.create = function create(o) {
var F = function(){};
F.prototype = o;
var result = new F();
F.prototype = null;
return result;
}
}

复制代码 代码如下:

但是呢,你不喜欢这样写,而倾向在对象的prototype中定义getters和setters(私有变量写在哪并不重要),我们可以用另一种语法。

您可能感兴趣的文章:

  • JavaScript原型继承_动力节点Java学院整理
  • JavaScript中的原型继承基础学习教程
  • javascript原型继承工作原理和实例详解
  • 浅析JS原型继承与类的继承
  • JavaScript的原型继承详解
  • 再谈javascript原型继承
  • js原型继承的两种方法对比介绍
  • 浅析JavaScript原型继承的陷阱
  • 关于JavaScript中原型继承中的一点思考
  • JavaScript 原型继承
  • 详谈js原型继承的一些问题

function Sandy(val){
var value = val,
_watch = function(newVal) {
console.log(‘val is Changed to : ‘ + newVal);
}

复制代码 代码如下:

this.__defineGetter__(“value”, function(){
return value;
});

function Field(val){
this.value = val;
}
Field.prototype = {
get value(){
return this._value;
},
set value(val){
this._value = val;
}
};

this.__defineSetter__(“value”, function(val){
value = val;
_watch(val);
});
}

这种语法看起来很不可思议,但是使用过一段时间之后,接受它也很容易。
接下来是另一个例子,它允许外界获取一个username数组,但是却不能获取原始的,隐藏的user对象。

var sandy = new Sandy(“test”);
sandy.value
// => test
sandy.value = “test2”;
// => ‘val is Changed to : test2’
sandy.value
// => “test2”

复制代码 代码如下:

 除了__defineG/Setter__外,
你还可以使用’set’、’get’关键字在在原型对象上定义accessor,对于单个对象同样适用,
适用于Firefox 2.0+, Safari 3.0+, Google Chrome 1.0+ 和 Opera 9.5+.

function Site(users){
this.__defineGetter__(“users”, function(){
// JS 1.6 Array map()
return users.map(function(user){
return user.name;
});
};
}

复制代码 代码如下:

作为福利,我写了一个方法,它可以帮你实现对象的继承,并且还考虑到了getters和setters

function Sandy(val){
this.value = val;
}

复制代码 代码如下:

Sandy.prototype = {
get value(){
return this._value;
},
set value(val){
this._value = val;
}
};

// Helper method for extending one object with another
function extend(a,b) {
for ( var i in b ) {
var g = b.__lookupGetter__(i), s = b.__lookupSetter__(i);
if ( g || s ) {
if ( g )
a.__defineGetter__(i, g);
if ( s )
a.__defineSetter__(i, s);
} else
a[i] = b[i];
}
return a;
}

//Or

在我的extend()方法中,你会发现两个新方法:__lookupGetter__和__lookupSetter__。一旦你真正开始使用getters和setters,这将很有用。
比如,当我第一次写extend()方法时,我遇到了各种errors,我彻底晕了。后来我发现问题就出在一个简单的语句上:a[i]
= b[i];
如果对象a存在一个setter,名字叫做i,对象b存在一个getter,名字也叫做i,a[i]不是通过别的setter方法赋值的,而是来自b的getter方法。这两个__lookup*__方法使你可以获取原始的函数。(这段翻得有点晦涩,原文如下)

var sandy = {
‘_value’ : ‘sandy’,
get value() {
  return this._value;
},
set value(val) {
  this._value = val;
}
}

If a setter existed in object a, named i, and a getter existed in object
b, named i, a[i]’s value was being set not to the other setter
function, but to the computed value from b’s getter function. The two
__lookup*__ methods allow you to access the original functions used
for the methods (thus allowing you to write an effective extend method,
for example).
  
记住以下几点
一个对象内,每个变量只能有一个getter或setter。(因此value可以有一个getter和一个setter,但是value绝没有两个getters)
删除getter或setter的唯一方法是:delete
object[name]。delete可以删除一些常见的属性,getters和setters。
如果使用__defineGetter__或__defineSetter__,它会重写之前定义的相同名称的getter或setter,甚至是属性(property)。
平台
支持的浏览器有
Firefox
Safari 3+
Opera 9.5
(原文没写Chrome,还没出呢)
我用下面的代码测试浏览器

最后一种方法,用到了Object的静态方法defineProperty,作用于单个对象,该方法应该属于ES5的范畴了,目前似乎只有Chrome
支持这种方法,其实Ie8也支持,但操作对象仅限于Dom节点(Dom
node),见IEBlog,该方法的使用见MDN.

复制代码 代码如下:

复制代码 代码如下:

javascript:foo={get test(){ return “foo”; }};alert(foo.test);

var sandy = {}, rValue;
Object.defineProperty(sandy, ‘value’ ,
{
‘set’ : function(val) {
rValue = val;
},
‘get’ : function() {
return rValue;
},
‘enumerable’ : true,
‘configurable’ : true
}
)
//Ie8+
Object.defineProperty(document.body, “description”, {
get : function () {
return this.desc;
},
set : function (val) {
this.desc = val;
}
});
document.body.description = “Content container”;
// document.body.description will now return “Content container”

另外,以下两种引擎也支持Getters和Setters:
SpiderMonkey
Rhino 1.6R6 (New)

‘enumerable’,’configuralbe’ 属于ES5规范中的Property
Attributes(属性特性),在这里就不做讨论了,有兴趣的Google或者直接去看ES5的文档.
^ ^

Resig早年的文章,大致翻译了一下,以作备忘。
令人高兴的是,我想我终于可以说,“现在,JavaScript的Getters和Setters使用非常广泛,…

您可能感兴趣的文章:

  • JavaScript使用ActiveXObject访问Access和SQL
    Server数据库
  • 静态页面下用javascript操作ACCESS数据库(读增改删)的代码
  • 用javascript连接access数据库的方法
  • JS连接SQL数据库与ACCESS数据库的方法实例
  • 用nodejs访问ActiveX对象,以操作Access数据库为例。
  • Javascript连接Access数据库完整实例

发表评论

电子邮件地址不会被公开。 必填项已用*标注