本文章记录本人在学习 JavaScript 中看书理解到的一些东西,加深记忆和而且整理记录下来,方便以后的复习。编程
说道代码复用,通常都会涉及到对象继承。在js
中有许多能够选择的继承方法。这些方法对于学习和理解多种不一样的模式有很大的好处,由于它们有助于提供对语言的掌握程度。数组
可是在开发的过程当中,并非全部的代码复用都会使用到继承。其中一部缘由在于,事实上使用的js
库可能以这样的或那样的方式解决了该问题。而另外一方面的缘由就在于不多须要在js
中创建长并且复杂的继承链。在静态强类型语言中,继承能够能是惟一复用代码的方法。在js
中,常常有更加简洁并且优美的方法。包括:借用方法、绑定、复制属性以及从多个对象中混入属性等许多方法。闭包
混入是针对经过属性复制实现继承的思想作进一步的扩展,mix-in
模式并非复制一个完整的对象,而是从多个对象中复制出任意的成员并将这些成员组合成新的对象。app
实现mix-in
:函数
function mix() { var arg, prop, child = {}; for (arg = 0; arg < arguments.length; arg += 1) { for (prop in arguments[arg]) { if (arguments[arg].hasOwnProperty(prop)) { child[prop] = arguemnts[arg][prop]; } } } return child; }
mix-in
实现很是简单,只须要遍历每一个参数,而且复制出传递给该函数的每一个对象中的每一个属性。学习
有的时候,咱们只须要对象中的一两个方法,可是又不想和对象造成父-子继承关系。只是想是用所须要的方法,而不但愿继承全部那些永远用不到的属性和方法。在这种状况下,能够经过使用借用方法模式来实现。测试
而这个方法是受益于call()
和apply()
的。js
中函数也是对象,而且它们自身也存在一些属性和方法,好比call
和apply()
。this
使用call()
和apply()
分别借用方法:prototype
// call notmyobj.doStuff.call(myobj, param1, p2, p3); // apply notmyobj.doStuff.apply(myobj, [param1, p2, p3]);
在知道notmyobj
对象上有doStuff
方法的状况下,又想不继承notmyobj
来使用doStuff
方法。这个使用call()
和apply()
就派上用场了。指针
还有一个场景是常用到借用方法的。那就是借用数组方法。由于数据具备许多很强大的方法,并且有时候须要操做arguments
的时候会用上。可是arguments
是一个伪数组,不具备原生数组强大的方法。这个使用借用方法就派上用场了:
function f() { var args = [].slice.call(arguemnts, 1, 3); return args; }
考虑到借用方法不是经过调用call
和apply()
就是经过简单的复制,在借用方法的内部,this
所指向的对象是基于调用表达式而肯定的,可是有的时候“锁定”this
的值,或者将其绑定到特定的对象而且预先肯定该对象。
举一栗子:
var one = { name: 'object', say: function (greet) { return greet + ", " + this.name; } }; // 测试 one.say('hi'); // hi, object
接着另外一对象two
中没有say()
方法,借用one
的say()
方法:
var two = { name: 'another object' } // 测试 one.say.call(two, 'hi'); // hi, another object
在上面的例子中,借用的say()
方法的this
是指向two
的。可是在什么样的场景中,应该将函数指针赋值给一个全局变量,或者将该函数作为回调函数来传递?在客户端编程中有许多事件和回调,所以确实发生了许多这样混淆的事件。
举一个栗子:
// 给变量赋值 // this 将指向全局变量 var say = one.say; say('hello') // hello, undefined // 做为回调传递 var yetanother = { name: 'yet another object', method: function (callback) { return callback('hola'); } }; // 测试 yetanother.method(one.say) // holla, undefined
在上面的两种状况下,say()
方法的this
值都是指向全局对象。并且整个代码都没法按照预期来运行。为了修复(绑定)对象与方法之间的关系。可使用一个简单的函数来实现:
function bind(o, m) { return function () { return m.apply(o, [].slice.call(arguments)) }
上面的bind()
方法接受两个参数。一个是对象o
,另外一个是方法m
,并将二者绑定起来。而后返回一个函数。
使用bind()
来解决问题:
var twosay = bind(two, one.say); twosay('yo'); // yo another object
奢侈的拥有绑定所须要辅助的代价就是额外的闭包的开销。
在ECMAScript5
中给Function.protoype
添加了一个bind()
方法,使得bind()
与call()、apply()
同样简单易用。
可是在不支持ECMAScript5
的运行环境下,咱们能够本身实现一个bind()
方法(来自 MDN):
if (!Function.prototype.bind) { Function.prototype.bind = function (oThis) { if (typeof this !== "function") { // closest thing possible to the ECMAScript 5 internal IsCallable function throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); } var aArgs = Array.prototype.slice.call(arguments, 1), fToBind = this, fNOP = function () {}, fBound = function () { return fToBind.apply(this instanceof fNOP && oThis ? this : oThis || window, aArgs.concat(Array.prototype.slice.call(arguments))); }; fNOP.prototype = this.prototype; fBound.prototype = new fNOP(); return fBound; }; }
而后使用自带的bind()
方法来重写一下上面的栗子:
var twosay = bind(two, one.say); twosay('Bonjour'); // yo another object
最后,若是文章有什么错误和疑问的地方,请指出。与sf各位共勉!