函数javascript
原型(prototype)css
thisjava
new的理解闭包
1.一、预处理阶段app
注意:js预处理阶段会扫描全部var声明的变量,把var声明的变量或函数存放到词法做用域里,若是是变量初始值为“undefined”,若是是函数则指向函数;ide
全局(window)函数
词法做用域(Lexical Environment):顶级的Lexical Environment是window;测试
一、先扫描函数声明后扫描变量(var声明);this
二、处理函数声明有冲突,会覆盖;处理变量声明时有冲突,会忽略。spa
函数
词法做用域(Lexical Environment):每调用一次,产生一个Lexical Environment;
一、先函数的参数:好比arguments(函数内部对象,表明函数实参,可经过下标获取调用函数时传的实参);
二、先扫描函数声明后扫描变量(var声明);
三、处理函数声明有冲突,会覆盖;处理变量声明时有冲突,会忽略。
1.二、执行阶段
一、给预处理阶段的成员赋值
二、若是没有用var声明的变量,会成为最外部LexicalEnvironment的成员(即window对象的变量)
函数内部对象:arguments
<script> /*提示:*/ // arguments是每个函数内部的一个对象 // 能够访问实际传递给函数的参数的信息。 // 声明的时候参数的个数与实际调用时无关 function add(a,b){ console.log(add.length);// 形参的个数 console.log(arguments.length);// 实际传过来的参数 var total = 0; for(var i = 0;i< arguments.length;i++){ total += arguments[i]; } return total;// 返回实参的总和 } // 调用时传的实参 var result = add(1,2,3,4,5); var result2 = add(1,2); console.log(result);// 15 console.log(result2);// 3 </script>
提示:js的做用域不是块级别的;js的做用域是函数级别的。
2.一、块做用域
2.二、函数做用域
2.三、动态做用域
2.四、词法做用域
代码示例:
<script> //js做用域 // 定义:用来查找变量的值的规则集;决定一个变量的范围 // 提示:js的做用域不是块级别的;js的做用域是函数级别的。 // javascript使用的是词法做用域,它的最重要的特征是它的定义过程发生在代码的书写阶段 /*如下js代码用当即调用写法(私有化),避免变量冲突*/ //一、块做用域:代码在花括号里面有效(js没有块做用域) (function(){ for(var i=0;i<5;i++){ var a = i ; } // 在花括号外面能够访问到i,a console.log(i);// 5 console.log(a);// 4 })(); //二、函数做用域:代码在function()函数的花括号里面有效 (function(){ var message = "函数外部的"; function fn(){ var message = "函数内部的"; console.log(message);// 函数内部的 } console.log(message);// 函数外部的 })(); //三、动态做用域:在运行时决定(是this指向的表现;谁调用,this指向谁);动态做用域实际上是指this的词法做用域 // 动态做用域并不关心函数和做用域是如何声明以及在任何处声明的,只关心它们从何处调用。 // 换句话说,做用域链是基于调用栈的,而不是代码中的做用域嵌套 (function(){ var a = 2; function foo() { console.log( a ); } function bar() { var a = 3; foo();// 此时this===window } bar();// 2 })(); /* var a = 2; bar = { a:3, foo:function(){ console.log(this.a); } } bar.foo();//3 */ //四、词法做用域:词法做用域(也称为静态做用域或闭包) // js的做用域解析,用new Function建立函数 (function(){ // 闭包 var a = 2; function bar() { var a = 3; return function(){ console.log(a);// 此时捕获a=3 }; } var foo = bar(); foo();// 3 })(); // 若是处于词法做用域,也就是如今的javascript环境。变量a首先在foo()函数中查找,没有找到。因而顺着做用域链到全局做用域中查找,找到并赋值为2。因此控制台输出2 // 若是处于动态做用域,一样地,变量a首先在foo()中查找,没有找到。这里会顺着调用栈在调用foo()函数的地方,也就是bar()函数中查找,找到并赋值为3。因此控制台输出3 //小结:两种做用域的区别,简而言之,词法做用域是在定义时肯定的,而动态做用域是在运行时肯定的 </script>
3.一、什么是闭包
因为在Javascript语言中,只有函数内部的子函数才能读取局部变量,所以能够把闭包简单理解成“定义在一个函数内部的函数,内部函数并访问父函数的局部变量”。
理解闭包:
一、闭包能够理解为一个对象,里面包含函数以及被函数捕获的变量 , 一个圈里包含函数与捕获的变量
二、也能够只把函数捕获的变量称之为闭包。
<script> //如何写会产生闭包 function P(){ var a = 5; var b = 6; return function C(){ console.log(b);//此时捕获变量b,值为6 } } var result = P(); result();// 6 </script>
产生闭包的条件:
一、函数内部包含子函数;
二、子函数访问父函数的变量;
3.二、闭包的好处
用途:一个是前面提到的能够读取函数内部的变量,另外一个就是让这些变量的值始终保持在内存中。
<script> // 闭包实例 function Person(){ var age = 1; this.getAge = function(){ return age ; } this.setAge = function(val){ age = val; } } var p = new Person(); p.setAge(20); console.log(p.getAge()); </script>
代码示例:
<script type="text/javascript"> /*闭包--理解*/ // 提示:this由运行时决定! // 题目一:理解r1与r2的输出 function addFactory(){ var adder = 5; return function(data){ adder += data;// 此时adder变量是闭包捕获到的值 return adder; } } var adder1 = addFactory(); var r1 = adder1(1);//6 r1 = adder1(1);//7 var adder2 = addFactory(); var r2 = adder2(2);//7 r2 = adder2(2);//9 // 题目二:下面的代码输出什么 var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ return function(){ return this.name;// 输出"The Window";this = window; //return object.name;// 输出"My object" }; } }; //alert(object.getNameFunc()());// The Window // 理解二: var fun = object.getNameFunc();// 返回一个函数,此时函数this指向window;window.fun() alert(fun());// 因此,输出是:"The Window" // 题目三: var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ var that = this;//this = object; return function(){ return that.name;//闭包捕获父函数的that,that = object; }; } }; alert(object.getNameFunc()());// My Object // 理解三: // var obj = object.getNameFunc(); // alert(obj());// 此时函数因为内部的name是object调用 </script>
4.一、对象
4.二、函数
4.三、原型(prototype)
javascript对象部署:
JavaScript是一种经过原型实现继承的语言;在JavaScript中全部都是对象,原型(prototype)也是一个对象,经过原型能够实现对象的属性继承;
prototype:在js中是函数特有的属性;指向该函数的原型(this.prototype)
__proto__:在js中是全部对象都有的属性;指向此对象的构造器(函数)的原型对象(prototype)
<!-- 对象都有这属性(找对象的父类对象):__proto__; 只有函数有的属性(找函数的原型,是个对象):prototype; 对象(或函数)的构造器(顶级构造器时Function()):constructor; --> <script> function Aaa(){} //undefined var aaa = new Aaa(); //undefined aaa.__proto__; //{constructor: ƒ} Aaa.prototype; //{constructor: ƒ} aaa.__proto__ === Aaa.prototype; //true aaa.constructor; //ƒ Aaa(){} Aaa.constructor; //ƒ Function() { [native code] } aaa.constructor.constructor //ƒ Function() { [native code] } </script>
原型理解:
1. 函数Foo的__proto的值等于Foo.prototype,对吗? 错,函数Foo.__proto__===Function.prototype,函数Foo的实例的__proto__属性的值等于函数Foo.prototype 2.Object的prototype能够修改吗?能与不能缘由是什么? //能够,函数(对象)的原型能够任意修改或继承 不能够,由于Object.prototype是只读,因此不能赋值;但能够修改或添加 3. 顶级constructor是谁? Function() 4.顶级原型对象是谁? Object 5.对象的construtor成员是个属性仍是个方法? 能够是属性,也能够是方法(通常不建议这么写,耗资源,在每次new是都要执行不少代码) 6.Function有没有__proto__,为何?值等于Object.prototype吗? 1.有(是对象都有),与prototype相等,由于Function是顶级构造器,因此,函数的__proto__属性指向的构造器原型是与Function.prototype相等; 2.不等于,Function.prototype与Function.__proto__指向function.prototype 7.全部的构造器的__proto__都等于其对应的prototype 错,等于Function.prototype;由于对象的__proto__属性指向的是对象的构造器的prototype(函数的构造器是Function()) 8.建立类形式的继承的四部曲是什么? 1.建立父类 2.建立子类 3.肯定继承关系:A.prototype = Object.create(B.prototype); 4.修改构造器(由于继承后的构造器指向是父类的原型指向的构造器,也就是说,子类的原型指向的构造器===父类的原型指向的构造器) 9.Function的constructor于prototype值能够修改吗? 不能够,Function是顶级构造器,Function.__proto__指向Function.prototype 10.Object.prototype === Object.__proto__吗? 不相等,Object.prototype是object.prototype;Object.__proto__是function.prototype 11. Function.prototype === Function.__proto__吗? 相等,(由于Function是顶级构造器,__proto__指向Function.prototype)Function.prototype===Function.__proto__ 12. function F(){}; var f1 = new F(); f1.__proto__ === Object.prototype吗? 不对,f1.__proto__ === F.prototype;f1.__proto__.__proto__ === Object.prototype;
4.五、this
原则:
一、this由运行时决定!
二、函数中 this 到底指向谁 , 由调用此函数时的对象决定 , 而不是由定义函数所在的对象决定。
在JavaScript中this表示:谁调用它,this就是谁。
如何改变this指向:
call:
apply:
<script> /* var data = {}; Array.prototype.push.call(data,100,200); Array.prototype.push.apply(data,[1,2,3,8,10]); console.log(data); */ </script>
4.六、new的理解
简单的能够理解为:new改变了this指向的对象;
<script type="text/javascript"> /* // 提示: // 暴露外部使用的一个接口 var jQuery = window.jQuery = window.$ = function(selector){ return new jQuery.fn.init(selector); } // 处理原型对象 jQuery.fn = jQuery.prototype = {} jQuery.fn.init.prototype = jQuery.fn; // 实现继承,而且只处理只有一个参数,也就是插件的扩展 jQuery.extend = jQuery.fn.extend = function(){} // 添加静态方法 jQuery.extend({}); // 添加实例方法 jQuery.fn.extend({}); // 1.获取节点对象 var jq1 = jQuery(".pp"); 或 var jq1 = jQuery.fn.init(".pp"); */ // 提供全局访问接口($()、jQuery()) (function () { /// 暂时把window的全局变量存起来,用作处理变量冲突 var _$ = window.$; var _jQuery = window.jQuery; //暴露外部使用的一个接口(获取节点对象) var jQuery = window.jQuery = window.$ = function(selector){ return new jQuery.fn.init(selector);// init.prototype; }; //处理原型对象 jQuery.fn = jQuery.prototype = { init:function(selector){ var elements = document.querySelectorAll(selector); Array.prototype.push.apply(this,elements); return this; }, version:"1.0.0", length:0, size:function(){ return this.length; } }; // jQuery.fn.init.prototype === init.prototype; // jQuery.prototype; jQuery.fn.init.prototype = jQuery.fn; //实现继承,而且只处理只有一个参数,也就是插件的扩展 jQuery.extend = jQuery.fn.extend = function(){ var o = arguments[0]; for(var p in o){ this[p] = o[p]; } }; /// 测试:(继承方法) // var obj = {name:"张三三"} // var jq = $(".pp"); // jq.extend(obj); //添加静态方法 jQuery.extend({ trim:function(text){ return (text||"").replace(/^\s+|\s+$/g,"");// 替换text字符串的开头和结尾匹配任何空白字符为空(即,替换开头和结尾的空格字符为空) }, noConflict:function(){ window.$ = _$; window.jQuery = _jQuery; return jQuery; } }); /// 测试:(命名冲突) // var jq = jQuery.noConflict();//返回一个jQuery函数,解决与全局的jQuery属性冲突 // var obj = jq(".pp"); //添加实例方法 jQuery.fn.extend({ get:function(num){ return this[num]; }, each:function(fn){ for(var i = 0 ;i< this.length; i++){ fn(i,this[i]); } return this; }, css:function(){ var l = arguments.length; if(l == 1){ return this[0].style[arguments[0]]; } else { var name = arguments[0]; var value = arguments[1]; this.each(function(index,ele) { ele.style[name] = value; }); } return this; } }); })(); </script>