很久很久以前,我还是个phper,第一次接触javascript觉得好神奇。跟传统的oo类概念差别很大。记得刚毕业面试,如何在javascript里面实现class一直是很热门的面试题,当前面试百度就被问到了,当年作为一个小白只是网上随便搜搜应付了下。= =现在发现当时知道的还是太少太少。今天整理了下javascript的oo实现,发现知道的越多,越发现知识真是无穷无尽。

原始时代最简单的oo实现

javascript虽然没有class的概念,但是它的函数却是可以new出来一个对象的。所以一个最简单的class就可以用function来模拟出来。


function Animal(name){
this.name = name;
this.run = function(){
console.log(this.name + "is running!!");
}
} var pet = new Animal("pet");
pet.run();//petis running!!

这样 pet就有了属性,有了方法,不过这种写法毫无继承性,扩展性。比如我们要实现个dog类,只能把属性方法再写一遍。而且每个new出来的对象都有自己的方法,造成资源浪费。

在javascript里面有个原型链的概念,每一个函数都有一个prototype对象属性。这样通过这个函数new出来的对象会自动具有__proto__属性指向函数的prototype对象。说白了所有的实例对象都会共用一个prototype对象,并且调用一个属性或者方法时在自己上面找不到,就会找__proto__对象有没有,之后一直往上追溯一直到找到为止。具体表现为:


function Animal(name){
this.name = name;
}
Animal.prototype.run = function(){
console.log(this.name + "is running!!");
}
var a = new Animal("a");
var b = new Animal("b");
console.log(Animal.prototype) //Animal {}
console.log(Animal.prototype instanceof Object) //true prototype是个对象
console.log(Animal.prototype.constructor == Animal)//true
console.log(a.__proto__ == Animal.prototype) //true __proto__在new的时候会自动加载在实例对象上。在现代浏览器里可以看到
console.log(b.__proto__ == Animal.prototype) //true
console.log(a.__proto__.__proto__) //Object {} 最后会找到最上面的boject对象
console.log(a.__proto__.run == a.run) //true
console.log(a.__proto__.run == Animal.prototype.run) //true

所以,在prototype对象上定义的方法会被所有实例共享,这不就是复用吗?

于是有了基于原型链的继承的写法:


function Animal(name){
this.name = name;
}
Animal.prototype.run = function(){
console.log(this.name + "is running!!");
}
function Dog(name){
//调用父类的构造函数,通过改变this指向将属性赋值到新的实例对象
Animal.call(this,name);
}
Dog.prototype = new Animal();
var dog = new Dog("dog");
dog.run();//dog is running!!

可以看到我们将Animal的实例对象暂且叫做a,作为 Dog的prototype,这样 Dog的实例对象dog的__proto__指向Dog的prototype也就是a,a的__proto__再指向Animal的prototype对象,这个对象上有run方法。于是我们调用dog.run()的时候会一层层的往上追溯一直找到run方法执行。于是通过原型链我们就让 Dog继承了Animal的方法run。

需要注意的是,如果在子类的prototype对象上也有run方法,就会覆盖父类的,因为查找时在自己上面就找到了,就不会向上回溯了。

上面是原型链方法的继承。而属性我们则是通过调用父类的构造函数来赋值的。因为属性不能所有的实例都公用,应该每个人都有自己的一份,所以不能放在原型上。

上面就是原始时代最简单的类继承了。

石器时代的oo实现

这个时代javascript变得比较重要了,作为非常有用的特性,oo开始被很多人研究。

首先上面的那种简单oo实现方式,其实是有很多问题的。

1.没有实现传统oo该有的super方法来调用父类方法。

作为oo,怎么能没有super呢。作为我们前端界宗师一般的人物。Douglas 有一篇经典文章。不过貌似有很多问题。国内的玉伯分析过。在这里

最后Douglas总结出来:

我编写 JavaScript 已经 8 个年头了,从来没有一次觉得需要使用 uber 方法。在类模式中,super 的概念相当重要;但是在原型和函数式模式中,super 的概念看起来是不必要的。现在回顾起来,我早期在 JavaScript 中支持类模型的尝试是一个错误。

2.直接将父类实例作为子类的原型,简单粗暴造成多余的原型属性。还有construct的问题。

这个问题主要是之前代码里面这一句造成的:


Dog.prototype = new Animal();
//var dog = new Dog("dog");
//console.log(dog.__proto__) Animal {name: undefined}

执行new Animal()就会执行animal的构造函数,就会在Dog.prototype生成多余的属性值,这边是name。而一般属性值为了复用是不能放在原型对象上的。并且由于dog有自己的name属性,原型上的是多余的。

还有construct的问题。


console.log(dog.constructor == Animal) //true
console.log(dog.constructor == Dog) //false

显然这不是我们希望看到的。

所以我们要对上面做些改良:


var F = function(){};
F.prototype = Animal.prototype;
Dog.prototype = new F();
Dog.prototype.constructor = Dog;

我们可以封装下:


function objCreate(prototype){
var F = function(){};
F.prototype = prototype;
return new F();
}
function inherit(subclass,parentclass){
subclass.prototype = objCreate(parentclass.prototype);
subclass.prototype.constructor = subclass;
}

于是继承可以写成:


function Animal(name){
this.name = name;
}
Animal.prototype.run = function(){
console.log(this.name + "is running!!");
}
function Dog(name){
//调用父类的构造函数,通过改变this指向将属性赋值到新的实例对象
Animal.call(this,name);
}
inherit(Dog,Animal);
var dog = new Dog("dog");
dog.run();//dog is running!!

当年大学毕业面试,也就到这个程度了。 = =

工业时代的oo实现

这个时代,各种javascript类库像雨后春笋般涌现了出来。

上面最后给出的方案,使用起来还是很不便,比如需要自己手动维护在构造函数里调用父类构造函数。同时继承写法对不了接原理的比较容易出错。

这个时候涌现了一大堆的类库的实现:

1.首先有些类库决定跳出传统oo的思维。不一定非要实现传统oo的继承。归根到底我们是为了复用。于是出现了很多轻量级的复用方式。

比如jquery的extend:http://api.jquery.com/jQuery.extend/

还有kissy的mix:http://docs.kissyui.com/1.3/docs/html/api/seed/kissy/mix.html?highlight=mix#seed.KISSY.mix

还有kissy的argument:http://docs.kissyui.com/1.3/docs/html/api/seed/kissy/augment.html

还有很多很多,说白了都是对象级别上的混入达到复用的地步。大部分情况下已经足够了。

2.当然还是有人对类的继承有需求的。

下面我们看下kissy的extend的实现方式。其他类库实现方式类似,kissy的我觉得算是比较有代表性了。为了演示,做了些小修改。


//这个就是我们之前实现的方法,为了演示做了些改动主要是处理了construct的问题
function objCreate(prototype,construct){
var F = function(){};
F.prototype = prototype;
var newPro = new F();
newPro.construct = construct;//维护构造函数的改变
return newPro;
}
//mix是个辅助方法,这边给个最简单的实现,其实kissy里面的复杂的多。这边不考虑深度遍历等等,只是最简单的实现。
function mix(r, s) {
for (var p in s) {
if (s.hasOwnProperty(p)) {
r[p] = s[p]
}
}
}
//下面是kissy的实现r代表子类 s代表父类,px代表最后会混入子类原型上的属性,sx代表会混入子类函数上面的属性,也就是可以当做静态方法。
//http://docs.kissyui.com/1.3/docs/html/api/seed/kissy/extend.html?highlight=extend#seed.KISSY.extend
function extend (r, s, px, sx) {
if (!s || !r) {
return r;
}
var sp = s.prototype,
rp;
//针对父类生成一个原型。跟之前我们写的一致
rp = createObject(sp, r);
//不是简单的直接复制原型对象,而是先把以前原型的方法跟要继承的合并之后再一起赋值
r.prototype = S.mix(rp, r.prototype); //为子类增加superclass属性,指向一个父类对象,这样就可以调用父类的方法了。这边是实现比较巧妙的地方
r.superclass = createObject(sp, s);
//下面就是往原型还有函数上混入方法了
// add prototype overrides
if (px) {
S.mix(rp, px);
} // add object overrides
if (sx) {
S.mix(r, sx);
} return r;
}

有了kissy的extend我们可以这么用:


function Animal(name){
this.name = name;
}
Animal.prototype.run = function(){
console.log(this.name + "is running!!");
}
function Dog(name){ //Animal.call(this,name);
//因为kissy的封装 这边可以这么用
Dog.superclass.construct.call(this,name);
}
extend(Dog,Animal,{
wang:function(){
console.log("wang wang!!")
}
})
var dog = new Dog("dog");
dog.run();//dog is running!!
dog.wang();//wang wang!!

相对之前的变得清晰了很多,也更易用了。

现代科技时代的oo实现

前面的写法,目前虽然还是有很多人用,不过也渐渐过时了。上面的写法还是不够清晰,定义属性,方法都很分散,也没有多继承,等特性。我们需要像传统oo一样具有一个类工厂,可以生成一个类,属性都定义在里面。同时具有继承的方法。

而随着javascript成为前端唯一的语言,一代代大神前仆后继。终于开始涌现出了各种神奇的写法,下面罗列下一些我觉得特别好的实现,加上原理注释。

John Resig的实现方式

作为jquery的作者。John Resig在博客里记录了一种class的实现,原文在此

调用方法:


var Person = Class.extend({
init: function(isDancing){
this.dancing = isDancing;
},
dance: function(){
return this.dancing;
}
}); var Ninja = Person.extend({
init: function(){
this._super( false );
},
dance: function(){
// Call the inherited version of dance()
return this._super();
},
swingSword: function(){
return true;
}
}); var p = new Person(true);
p.dance(); // => true var n = new Ninja();
n.dance(); // => false
n.swingSword(); // => true // Should all be true
p instanceof Person && p instanceof Class &&
n instanceof Ninja && n instanceof Person && n instanceof Class
源码解读: /* Simple JavaScript Inheritance
* By John Resig http://ejohn.org/
* MIT Licensed.
*/
// Inspired by base2 and Prototype
(function(){
//initializing是为了解决我们之前说的继承导致原型有多余参数的问题。当我们直接将父类的实例赋值给子类原型时。是会调用一次父类的构造函数的。所以这边会把真正的构造流程放到init函数里面,通过initializing来表示当前是不是处于构造原型阶段,为true的话就不会调用init。
//fnTest用来匹配代码里面有没有使用super关键字。对于一些浏览器`function(){xyz;}`会生成个字符串,并且会把里面的代码弄出来,有的浏览器就不会。`/xyz/.test(function(){xyz;})`为true代表浏览器支持看到函数的内部代码,所以用`/\b_super\b/`来匹配。如果不行,就不管三七二十一。所有的函数都算有super关键字,于是就是个必定匹配的正则。
var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/; // The base Class implementation (does nothing)
// 超级父类
this.Class = function(){}; // Create a new Class that inherits from this class
// 生成一个类,这个类会具有extend方法用于继续继承下去
Class.extend = function(prop) {
//保留当前类,一般是父类的原型
//this指向父类。初次时指向Class超级父类
var _super = this.prototype; // Instantiate a base class (but only create the instance,
// don't run the init constructor)
//开关 用来使原型赋值时不调用真正的构成流程
initializing = true;
var prototype = new this();
initializing = false; // Copy the properties over onto the new prototype
for (var name in prop) {
// Check if we're overwriting an existing function
//这边其实就是很简单的将prop的属性混入到子类的原型上。如果是函数我们就要做一些特殊处理
prototype[name] = typeof prop[name] == "function" &&
typeof _super[name] == "function" && fnTest.test(prop[name]) ?
(function(name, fn){
//通过闭包,返回一个新的操作函数.在外面包一层,这样我们可以做些额外的处理
return function() {
var tmp = this._super; // Add a new ._super() method that is the same method
// but on the super-class
// 调用一个函数时,会给this注入一个_super方法用来调用父类的同名方法
this._super = _super[name]; // The method only need to be bound temporarily, so we
// remove it when we're done executing
//因为上面的赋值,是的这边的fn里面可以通过_super调用到父类同名方法
var ret = fn.apply(this, arguments);
//离开时 保存现场环境,恢复值。
this._super = tmp; return ret;
};
})(name, prop[name]) :
prop[name];
} // 这边是返回的类,其实就是我们返回的子类
function Class() {
// All construction is actually done in the init method
if ( !initializing && this.init )
this.init.apply(this, arguments);
} // 赋值原型链,完成继承
Class.prototype = prototype; // 改变constructor引用
Class.prototype.constructor = Class; // 为子类也添加extend方法
Class.extend = arguments.callee; return Class;
};
})();

相当简单高效的实现方式,super的实现方式非常亮

P.js的实现

源地址:https://github.com/jneen/pjs

pjs的一大亮点是支持私有属性,他的类工厂传递的是函数不是对象。

调用方式:


//可以生成一个可继承的对象,P接收一个函数,这个函数会传入生成后的class的原型。
var Animal = P(function(animal) {
animal.init = function(name) { this.name = name; }; animal.move = function(meters) {
console.log(this.name+" moved "+meters+"m.");
}
});
//继承Animal。后面的snake,animal分别是前面Snake和Animal的原型。程序直接把这些对象暴露给你了。于是灵活度很高。
var Snake = P(Animal, function(snake, animal) {
snake.move = function() {
console.log("Slithering...");
animal.move.call(this, 5);
};
}); var Horse = P(Animal, function(horse, animal) {
//真正的私有属性,外面没法调用到
var test = "hello world";
horse.move = function() {
console.log(test);
console.log("Galloping...");
//调用父类的方法,so easy!!
animal.move.call(this, 45);
};
});
//工厂方式生成对象,可以不用new
var sam = Snake("Sammy the Python")
, tom = Horse("Tommy the Palomino")
; sam.move()
tom.move()

源码解读:


var P = (function(prototype, ownProperty, undefined) {
return function P(_superclass /* = Object */, definition) {
// handle the case where no superclass is given
if (definition === undefined) {
definition = _superclass;
_superclass = Object;
} //最后返回的类就是这个,也就是我们需要的子类。这个类可以用new生成实例,也可以直接调用生成实例
function C() {
//判断,是new的话this instanceof C就是true。否则我们自己手动new一下Bare。Bare就是为了实现这种类工厂的生成类的方式
var self = this instanceof C ? this : new Bare;
self.init.apply(self, arguments);
return self;
} //这个就是用来实现不用new生成类的方式
function Bare() {}
C.Bare = Bare; //将父类的原型赋值给Bare
//这边prototype就是个字符串“prototype”变量,主要为了压缩字节少点,所以作者还单独传成变量进来 = =
var _super = Bare[prototype] = _superclass[prototype];
//再生成这个空函数的实例赋值给C,Bare的原型,同时在C.p存下来
//这样C,Bare都公用一个原型
var proto = Bare[prototype] = C[prototype] = C.p = new Bare; var key;
//改变constructor指向
proto.constructor = C;
//上面几部其实还是实现的通用的继承实现方式,新建个空函数,将父类的原型赋给这个空函数再生成实例赋值给子类的原型。万变不离其宗。原理都一样
//增加extend方法。这是个语法糖,本质上还是调用P来实现,只不过第一个参数是调用者C
C.extend = function(def) { return P(C, def); }
//下面是最关键的地方,写的有点绕。这边分为这几步
//传入definition 执行 function(def){}
// 执行C.open = C
// return C.open 其实就是 renturn C 返回最终的生成类
return (C.open = function(def) {
if (typeof def === 'function') {
// call the defining function with all the arguments you need
// extensions captures the return value.
//是函数的话就传入 一些属性包括子类原型,父类原型,子类构造函数,父类构造函数
def = def.call(C, proto, _super, C, _superclass);
} // 如果是对象,就直接混入到原型
if (typeof def === 'object') {
for (key in def) {
if (ownProperty.call(def, key)) {
proto[key] = def[key];
}
}
} //确保有init函数
if (!('init' in proto)) proto.init = _superclass; return C;
})(definition);
} })('prototype', ({}).hasOwnProperty);

阿拉蕾的实现方式

这是支付宝的库阿拉蕾的实现,我觉得是最不错的一种方式:

源地址:https://github.com/aralejs/class/blob/master/class.js


// The base Class implementation.
function Class(o) {
//这个判断用来支持 将一个已有普通类转换成 阿拉蕾的类
if (!(this instanceof Class) && isFunction(o)) {
//原理是给这个函数增加extend,implement方法
return classify(o)
}
}
//用来支持 commonjs的模块规范。
module.exports = Class // Create a new Class.
//
// var SuperPig = Class.create({
// Extends: Animal,
// Implements: Flyable,
// initialize: function() {
// SuperPig.superclass.initialize.apply(this, arguments)
// },
// Statics: {
// COLOR: 'red'
// }
// })
//
// //用于创建一个类,
//第一个参数可选,可以直接创建时就指定继承的父类。
//第二个参数也可选,用来表明需要混入的类属性。有三个特殊的属性为Extends,Implements,Statics.分别代表要继承的父类,需要混入原型的东西,还有静态属性。
Class.create = function(parent, properties) {
//创建一个类时可以不指定要继承的父类。直接传入属性对象。
if (!isFunction(parent)) {
properties = parent
parent = null
} properties || (properties = {})
//没有指定父类的话 就查看有没有Extends特殊属性,都没有的话就用Class作为父类
parent || (parent = properties.Extends || Class)
properties.Extends = parent // 子类构造函数的定义
function SubClass() {
// 自动帮忙调用父类的构造函数
parent.apply(this, arguments) // Only call initialize in self constructor.
//真正的构造函数放在initialize里面
if (this.constructor === SubClass && this.initialize) {
this.initialize.apply(this, arguments)
}
} // Inherit class (static) properties from parent.
//parent为Class就没必要混入
if (parent !== Class) {
//将父类里面的属性都混入到子类里面这边主要是静态属性
mix(SubClass, parent, parent.StaticsWhiteList)
} // Add instance properties to the subclass.
//调用implement将自定义的属性混入到子类原型里面。遇到特殊值会单独处理,真正的继承也是发生在这里面
//这边把属性也都弄到了原型上,因为这边每次create或者extend都会生成一个新的SubClass。所以倒也不会发生属性公用的问题。但是总感觉不大好
implement.call(SubClass, properties) // Make subclass extendable.
//给生成的子类增加extend和implement方法,可以在类定义完后,再去继承,去混入其他属性。
return classify(SubClass)
} //用于在类定义之后,往类里面添加方法。提供了之后修改类的可能。类似上面defjs实现的open函数。
function implement(properties) {
var key, value for (key in properties) {
value = properties[key]
//发现属性是特殊的值时,调用对应的处理函数处理
if (Class.Mutators.hasOwnProperty(key)) {
Class.Mutators[key].call(this, value)
} else {
this.prototype[key] = value
}
}
} // Create a sub Class based on `Class`.
Class.extend = function(properties) {
properties || (properties = {})
//定义继承的对象是自己
properties.Extends = this
//调用Class.create实现继承的流程
return Class.create(properties)
} //给一个普通的函数 增加extend和implement方法。
function classify(cls) {
cls.extend = Class.extend
cls.implement = implement
return cls
} // 这里定义了一些特殊的属性,阿拉蕾遍历时发现key是这里面的一个时,会调用这里面的方法处理。
Class.Mutators = {
//这个定义了继承的真正操作代码。
'Extends': function(parent) {
//这边的this指向子类
var existed = this.prototype
//生成一个中介原型,就是之前我们实现的objectCreat
var proto = createProto(parent.prototype) //将子类原型有的方法混入到新的中介原型上
mix(proto, existed) // 改变构造函数指向子类
proto.constructor = this // 改变原型 完成继承
this.prototype = proto //为子类增加superclass属性,这样可以调用父类原型的方法。
this.superclass = parent.prototype
},
//这个有点类似组合的概念,支持数组。将其他类的属性混入到子类原型上
'Implements': function(items) {
isArray(items) || (items = [items])
var proto = this.prototype, item while (item = items.shift()) {
mix(proto, item.prototype || item)
}
},
//传入静态属性
'Statics': function(staticProperties) {
mix(this, staticProperties)
}
} // Shared empty constructor function to aid in prototype-chain creation.
function Ctor() {
} // 这个方法就是我们之前实现的objectCreat,用来使用一个中介者来处理原型的问题,当浏览器支持`__proto__`时可以直接使用。否则新建一个空函数再将父类的原型赋值给这个空函数,返回这个空函数的实例
var createProto = Object.__proto__ ?
function(proto) {
return { __proto__: proto }
} :
function(proto) {
Ctor.prototype = proto
return new Ctor()
} // Helpers 下面都是些辅助方法,很简单就不说了
// ------------ function mix(r, s, wl) {
// Copy "all" properties including inherited ones.
for (var p in s) {
//过滤掉原型链上面的属性
if (s.hasOwnProperty(p)) {
if (wl && indexOf(wl, p) === -1) continue // 在 iPhone 1 代等设备的 Safari 中,prototype 也会被枚举出来,需排除
if (p !== 'prototype') {
r[p] = s[p]
}
}
}
} var toString = Object.prototype.toString var isArray = Array.isArray || function(val) {
return toString.call(val) === '[object Array]'
} var isFunction = function(val) {
return toString.call(val) === '[object Function]'
} var indexOf = Array.prototype.indexOf ?
function(arr, item) {
return arr.indexOf(item)
} :
function(arr, item) {
for (var i = 0, len = arr.length; i < len; i++) {
if (arr[i] === item) {
return i
}
}
return -1
}

万变不离其宗,本质上还是我们之前的继承方式,只是在上面再封装一层,更加清晰,明白了。

还有很多很多的实现,这边就不一一列举了。

未来科技的oo实现

其实 es6已经开始重视emcsript的oo实现了。不过还没定案,就算定案了,也不知道嘛时候javascript会实现。再加上一大堆浏览器的跟进。不知道什么时候才能用的上。不过了解下最新的规范还是很有必要的。

目前nodejs里面已经实现了 inherite方法用来实现类继承,类似我们上面的那种实现。

而es6(harmony)实现了class关键字用来创建类,并且具有类该有的一系列方法。如下:


class Monster {
// The contextual keyword "constructor" followed by an argument
// list and a body defines the body of the class’s constructor
// function. public and private declarations in the constructor
// declare and initialize per-instance properties. Assignments
// such as "this.foo = bar;" also set public properties.
constructor(name, health) {
public name = name;
private health = health;
} // An identifier followed by an argument list and body defines a
// method. A “method” here is simply a function property on some
// object.
attack(target) {
log('The monster attacks ' + target);
} // The contextual keyword "get" followed by an identifier and
// a curly body defines a getter in the same way that "get"
// defines one in an object literal.
get isAlive() {
return private(this).health > 0;
} // Likewise, "set" can be used to define setters.
set health(value) {
if (value < 0) {
throw new Error('Health must be non-negative.')
}
private(this).health = value
} // After a "public" modifier,
// an identifier optionally followed by "=" and an expression
// declares a prototype property and initializes it to the value
// of that expression.
public numAttacks = 0; // After a "public" modifier,
// the keyword "const" followed by an identifier and an
// initializer declares a constant prototype property.
public const attackMessage = 'The monster hits you!';
}

可以看到具有了传统oo里面的大部分关键字,私有属性也得到了支持。

继承也很容易:


class Base {}
class Derived extends Base {} //Here, Derived.prototype will inherit from Base.prototype. let parent = {};
class Derived prototype parent {}

原文在这里:http://h3manth.com/content/classes-javascript-es6

结语

虽然es6已经实现了正规的class关键字。不过等到真正能用上也不知道是何年马月了。不过规范提供了方向,在es6还没出来之前,n多大神前仆后继实现了自己的class方式,分析源码可以学到的还是很多,仅仅一个类的实现就可以抠出这么多的类容,程序员还是应该多探索,不能只停留在表面。

原文地址:https://github.com/purplebamboo/blog/issues/14

javascript oo实现的更多相关文章

  1. javascript oo实现(转)

    javascript oo实现 By purplebamboo 7月 13 2014 更新日期:8月 21 2014 文章目录 1. 原始时代最简单的oo实现 2. 石器时代的oo实现 3. 工业时代 ...

  2. javascript组件化(转)

    javascript组件化(转) By purplebamboo 3月 16 2015 更新日期:3月 23 2015 文章目录 1. 最简陋的写法 2. 作用域隔离 3. 面向对象 4. 抽象出ba ...

  3. javascript组件开发之基类继承实现

    上一篇文章大概的介绍了一下关于javascript组件的开发方式,这篇文章主要详细记一下基类的编写,这个基类主要是实现继承的功能 为什么要封装基类? 由于这次重构项目需要对各种组件进行封装,并且这些组 ...

  4. (转)javascript组件开发方式

    作为一名前端工程师,写组件的能力至关重要.虽然javascript经常被人嘲笑是个小玩具,但是在一代代大牛的前仆后继的努力下,渐渐的也摸索了一套组件的编写方式. 下面我们来谈谈,在现有的知识体系下,如 ...

  5. Python 与 Javascript 之比较

    最近由于工作的需要开始开发一些Python的东西,由于之前一直在使用Javascript,所以会不自觉的使用一些Javascript的概念,语法什么的,经常掉到坑里.我觉得对于从Javascript转 ...

  6. [转] javascript组件开发方式

    作为一名前端工程师,写组件的能力至关重要.虽然JavaScript经常被人嘲笑是个小玩具,但是在一代代大牛的前仆后继的努力下,渐渐的也摸索了一套组件的编写方式. 下面我们来谈谈,在现有的知识体系下,如 ...

  7. javascript 组件化(转载)

    这边只是很简陋的实现了类的继承机制.如果对类的实现有兴趣可以参考我另一篇文章javascript oo实现 我们看下使用方法: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ...

  8. Python 与 Javascript 比较

    最近由于工作的需要开始开发一些Python的东西,由于之前一直在使用Javascript,所以会不自觉的使用一些Javascript的概念,语法什么的,经常掉到坑里.我觉得对于从Javascript转 ...

  9. 前端js面向对象编程以及封装组件的思想

    demo-richbase 用来演示怎么使用richbase来制作组件的例子 作为一名前端工程师,写组件的能力至关重要.虽然javascript经常被人嘲笑是个小玩具,但是在一代代大牛的前仆后继的努力 ...

随机推荐

  1. windows cmd 透明化

    1 . 属性 -- 颜色 --不透明度 2 . 快捷键 : Ctrl+Shift+加号/减号 3. cmd 下快速查找文件 : dir a.txt /S

  2. 获取跨域请求的自定义的response headers

    一般情况下,使用ajax的getAllResponseHeaders这个方法只能得到response headers中的content-type的信息,其他服务器端放入response header中 ...

  3. java里如何实现两个等长度的字符串数组有多少个元素相同(从最左边开始,一旦遇到不同元素则跳出计数)

    不多说,直接上干货! package zhouls.bigdata.DataFeatureSelection.sim; public class test { public static int st ...

  4. ForkJoin有参无返回值、有参有返回值实例

    介绍: a . Fork/Join为JKD1.7引入,适用于对大量数据进行拆分成多个小任务进行计算的框架,最后把所有小任务的结果汇总合并得到最终的结果 b . 相关类 public abstract ...

  5. VMware Workstation Pro 14注册码,亲测可用

    ** VMware Workstation Pro 14注册码 ** 作者网上搜集整理 作者使用的密钥是: AC5XK-0ZD4H-088HP-9NQZV-ZG2R4 亲测可用 以下密钥未测试 CG5 ...

  6. js为页面元素添加水印

    近期有需求为页面部分区域添加上水印,通过在网上找到了js为页面添加水印的方法,后来经过自己的改进,可以实现为页面部分元素添加水印,最终效果如下图: 代码如下: function watermark(s ...

  7. jQuery事件绑定函数:on()与bind()的差别

    jQuery从1.7+版本开始,提供了on()和off()进行事件处理函数的绑定和取消.on()和bind()这两个方法有相同的地方也有不同的地方. bind(type,[data],fn); on( ...

  8. FRM-92050错误

    使用IE8在打开EBS Form界面时,窗口提示信息“Internet Explorer 已对此页面进行了修改,以帮助阻止跨站脚本.单击此处,获取详细信息...”或者R12 IE8中出"FR ...

  9. 如何使用VS将项目生成一个安装包?

    VS2010项目的部署与安装winform程序,我想进行安装.1.在解决方案中 ——点击右键——添加 2.然后选择 安装和部署 ——安装向导 可以更改名称 3.点击 下一步 4.然后选择上那3个 5. ...

  10. IUserStore------Implements Diagram