做者:zccst
2014-6-10
昨天对Array.prototype.slice.call(arguments);仍是不太理解,不知道为何slice调用时,能够将arguments切为数组。
今天理解call(this, args);中的this是一个对象。而不是一个函数function(){}。
- var test1 = {
- age : 10,
- sum : function(){
- return this.age;
- }
- }
- console.log(Array.prototype.slice.call(test1));
-
-
- function test2(){
- this.age = 10;
- this.sum =function(){
- return this.age;
- }
- }
- console.log(Array.prototype.slice.call(test2));
-
-
- var test3 = {
- 0 : 10,
- 1 : function(){
- return this[0];
- },
- length:2
- }
- console.log(Array.prototype.slice.call(test3));
-
-
- function Product(name, price) {
- this.name = name;
- this.price = price;
-
- if (price < 0)
- throw RangeError('Cannot create product "' + name + '" with a negative price');
- return this;
- }
-
- function Food(name, price) {
- console.log(this);
- Product.call(this, name, price);
- this.category = 'food';
- }
- Food.prototype = Object.create(Product.prototype);
-
- function Toy(name, price) {
- console.log(this);
- Product.call(this, name, price);
- this.category = 'toy';
- }
- Toy.prototype = Object.create(Product.prototype);
-
- var cheese = new Food('feta', 5);
- var fun = new Toy('robot', 40);
2014-6-9
从新看之前call的文章,以为call应该就是指定某一个函数在某一个做用域中执行。
好比:Array.prototype.slice.call(arguments);
jquery的proxy的实现
- proxy: function( fn, context ) {
- var tmp, args, proxy;
-
- if ( typeof context === "string" ) {
- tmp = fn[ context ];
- context = fn;
- fn = tmp;
- }
-
-
-
- if ( !jQuery.isFunction( fn ) ) {
- return undefined;
- }
-
-
- args = core_slice.call( arguments, 2 );
- proxy = function() {
- return fn.apply( context || this, args.concat( core_slice.call( arguments ) ) );
- };
-
-
- proxy.guid = fn.guid = fn.guid || jQuery.guid++;
-
- return proxy;
- }
2013-8-21
call和apply,它们的做用都是将函数绑定到另一个对象上去运行
二者的格式和参数定义:
call( thisArg [,arg1,arg2,… ] ); // 参数列表,arg1,arg2,...
apply(thisArg [,argArray] ); // 参数数组,argArray
上面两个函数内部的this指针,都会被赋值为thisArg,这可实现将函数做为另一个对象的方法运行的目的
1、call 的简单用法
首先,咱们先看个简单的例子(call):
- <!doctype html>
- <html>
- <head>
- <title> call-apply </title>
- </head>
-
- <body>
- <input type="text" id="idTxt" value="input text">
-
- <script type="text/javascript">
- var value = "global var";
-
- function mFunc()
- {
- this.value = "member var";
- }
-
- function gFunc()
- {
- alert(this.value);
- }
-
- window.gFunc(); // show gFunc, global var
- gFunc.call(window); // show gFunc, global var
- gFunc.call(new mFunc()); // show mFunc, member var
- gFunc.call(document.getElementById('idTxt')); // show element, input text
- </script>
-
- <script language="javascript">
- var func = new function()
- {
- this.a = "func";
- }
-
- var func2 = function(x)
- {
- var a = "func2";
- alert(this.a);
- alert(x);
- }
-
- func2.call(func, "func2"); // show func and func2
- </script>
- </body>
- </html>
而后,运行结果以下:
global var
global var
member var
input text
func
func2
测试环境:Google Chrome 10.0.648.45
最后,分析结果
一、全局对象window调用函数gFunc,this指向window对象,所以this.value为global var
二、函数gFunc调用call方法,this默认指向第一个参数window对象,所以this.value也为global var
三、函数gFunc调用call方法,this默认指向第一个参数new mFunc(),即mFunc的对象,所以this.value为mFunc的成员变量member var
四、函数gFunc调用call方法,this默认指向第一个参数input text控件,即id=‘idTxt’的控件,所以this.value为input控件的value值input text
五、函数func2调用call方法,this默认指向第一个参数func函数对象,所以this.value为this.a,即func
六、函数func2调用call方法,第二个参数属于函数对象func2的参数,所以alert(x)为第二个参数func2
2、call 继承用法与改进
js使用call模拟继承
测试代码:
- <!doctype html>
- <html>
- <head>
- <title> call - apply for inherit </title>
- </head>
-
- <body>
- <script type="text/javascript">
- function baseA() // base Class A
- {
- this.member = "baseA member";
- this.showSelfA = function()
- {
- window.alert(this.member);
- }
- }
-
- function baseB() // base Class B
- {
- this.member = "baseB member";
- this.showSelfB = function()
- {
- window.alert(this.member);
- }
- }
-
- function extendAB() // Inherit Class from A and B
- {
- baseA.call(this); // call for A
- baseB.call(this); // call for B
- }
-
- window.onload = function()
- {
- var extend = new extendAB();
- extend.showSelfA(); // show A
- extend.showSelfB(); // show B
- }
- </script>
- </body>
- </html>
运行结果以下:
baseB member
baseB member
测试环境:Google Chrome 10.0.648.45
结果分析:
预期的结果,应该是输出 baseA member 和 baseB member,但实际输出倒是 baseB member 和 baseB member
(已在IE九、八、6,Maxthon、Chrome、FF、Opera、Safari、360等浏览器测试过,结果都是后者:baseB member)
至此,机器是不会错的,这就须要咱们深刻分析
咱们可能会很容易想到是this引发的,this两次都指向了baseB对象,可是推测真是这样吗?
为了探究实质,咱们借助chrome浏览器的调试工具,下断点,进行调试,结果发现:
当调用extend.showSelfA();时,此时的this指向extendAB(并非咱们推测的两次都指向baseB对象)
真实缘由是extendAB对象的成员变量member在被baseB.call(this);实例化时,被baseB的成员member覆盖了,即extendAB的成员member由baseA member赋值成了baseB member
固然,咱们也能够对上面baseA代码稍做修改,来验证咱们调试分析的正确性:
- function baseA()
- {
- this.memberA = "baseA member";
- this.showSelfA = function()
- {
- window.alert(this.memberA);
- }
- }
再次运行chrome等浏览器,结果以下:
baseA member
baseB member
结果和咱们的预期相同,同时chrome调试信息也验证了咱们的正确性:
继承改进(prototype)
以上模拟继承方法,仔细分析不是最好的。
由于每次在函数(类)中定义了成员方法,都会致使实例有副本,所以能够借助prototype原型,进行改进
改进举例以下:
- <!doctype html>
- <html>
- <head>
- <title> call - apply for prototype </title>
- </head>
-
- <body>
- <script type="text/javascript">
- var Class = {
- create: function() // create Function
- {
- return function()
- {
- this.initialize.apply(this, arguments);
- }
- }
- };
-
- var Person = Class.create(); // Create Class Person
- /*至关于
- var Person = function(){
- this.initialize.apply(this, arguments);
- }
- */
- Person.prototype = { // prototype initialize
- initialize: function(obj1, obj2)
- {
- this.obj1 = obj1;
- this.obj2 = obj2;
- },
- showSelf: function()
- {
- alert("obj: " + this.obj1 + " and " + this.obj2);
- }
- }
-
- // instance Class
- var person = new Person("man", "women"); // two params
- person.showSelf(); // show person
- </script>
- </body>
- </html>
运行结果以下: obj: man and women