一、 重要:js中的function函数声明、函数表达式

// 函数声明
// Ex: 会在代码执行之前提前加载到作用域中,即js解析器会优先读取,确保在所有代码执行之前声明已经被解析;所以可以在定义之前调用。
function test(){
document.write("test() invoke!" + "<br>");
}
// 函数表达式
// Ex: 在代码执行到那一行的时候才会有定义;定义之后才能调用。
var t2 = function(){
document.write("t2() invoke!" + "<br>");
}
//函数声明:会在代码执行之前提前加载到作用域中
test("1"+name); // test() invoke!14
var name =1;
function test(name){
document.write("test() invoke!" + name + "<br>");
}
name=2;
test("2"+name); //test() invoke!22 //函数表达式:在代码执行到那一行的时候才会有定义
var t2;
//t2(); // t2 is not a function
test("21"+name); //test() invoke!212
name =3;
test("22"+name); //test() invoke!223
t2 = function(){
document.write("t2() invoke!" + "<br>");
} t2(); //正确 t2() invoke! name=4;
test("3"+name); //test() invoke!34

分析

1. 为什么是 test() invoke!14?

Js顺序逐行解析完后,name=4, 所以是 test() invoke!14

2. 执行test("2"+name);前 name =2;

// 函数表达式后面可以加括号立即调用该函数,函数声明不可以,只能以fnName()形式调用 

fnName();
function fnName(){
...
}//正常,因为‘提升’了函数声明,函数调用可在函数声明之前 fnName();
var fnName=function(){
...
}//报错,变量fnName还未保存对函数的引用,函数调用必须在函数表达式之后 var fnName;
fnName();
fnName =function(){
...
}//报错,变量fnName还未保存对函数的引用,函数调用必须在函数表达式之后 var fnName=function(){
alert('Hello World');
}();//函数表达式后面加括号,当javascript引擎解析到此处时能立即调用函数 function fnName(){
alert('Hello World');
}(1);//不会报错,但是javascript引擎只解析函数声明,忽略后面的括号,函数声明不会被调用 function(){
console.log('Hello World');
}();//语法错误,虽然匿名函数属于函数表达式,但是未进行赋值操作,
//所以javascript引擎将开头的function关键字当做函数声明,报错:要求需要一个函数名
// 问题:   它们之间的区别是什么?都会解析到就立即调用,是只参数位置不同。

(function test(arg){
document.write(arg + "<br>");
}("111")); //传说中推荐写法 (function test(arg){
document.write(arg + "<br>");
})("222"); //Jquery写法

二、 Js中的私有作用域 和闭包

资料:http://www.jb51.net/article/24101.htm

闭包:在内部定义的函数和变量只能在此范围内有效。形成是否是私有变量的概念。

var i=3;
function init(pa){
alert("外层init:"+i+","+pa);
} (function(pa) {
//私有作用域
var i=2;
//i=2;//这不是私有变量,会修改外层的i
function init(){
alert("内层init:"+i+","+pa);
}
init(); //内层init:2,lyn
})('lyn'); init("vergil");//外层init:3,vergil

闭包含义:

闭包就是能够读取其他函数内部变量的函数。

由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数”。

所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

什么是闭包:

function f1(){
var n=999;
add=function(){//没用var声明,表示是全局变量。 匿名表达式
n+=1;
}
function f2(){
document.write(n+"<br>");
}
return f2;
}
var result=f1();//result指向的是f1()的返回值,不是f1,二是f2的匿名
result();// 999
add();
result();//

f2函数就是闭包,f2可以访问f1的内部变量n。

函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。

原因:在于f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后被垃圾回收机制(garbage collection)回收。

当内部函数在定义它的作用域的外部被引用时,就创建了该内部函数的闭包;

如ex,f2定义在f1内部,但在f1的外部被引用了,既result();

如果内部函数引用了外部函数的变量,当外部函数调用完毕后,这些变量在内存不会被释放,因为闭包需要它们.

如ex,f2函数内部使用了外部的n;在var result=f1();调用完后。result指向f2,f1()结束调用。但此时不会释放局部变量n;因为n还被f2所用。

闭包注意事项

1) 由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。

解决方法: 在退出函数之前,将不使用的局部变量全部删除。

2) 闭包会在父函数外部,改变父函数内部变量的值。

所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

通过Jquery源码理解闭包/私有变量:

// Jquery的定义可以理解为:
(function(){
var a=...
})(jQuery);
// 此时,保护了内部的a不会被外部/全局变量修改。

几个理解js闭包的示例:

1、

var name = "The Window";
var object = {
  name : "My Object",
  getNameFunc : function(){
    return function(){
      return this.name;
   };
  }
};
alert(object.getNameFunc()()); //The Window

解析: object.getNameFunc()()实质, var temp = object.getNameFunc();

temp() 等价于 window.temp(); // 此时调用的this是window,即全局变量

2、

function outerFun()
{
var a=0;
function innerFun()
{
a++;
alert(a);
}
}
innerFun(); //error

解析:outerFun外部无法调用内部方法。

3、

function outerFun()
{
var a=0;
function innerFun()
{
a++;
alert(a);
}
return innerFun; //注意这里
}
var obj1=outerFun();
obj1(); //
obj1(); //
var obj2=outerFun();
obj2(); //
obj2(); //

解析: JS对象之间是独立的

三、 Js中的私有变量 (结合闭包理解)

资料:http://www.cnblogs.com/zhaobing/archive/2014/07/10/3836698.html

1. 特权函数构造器

name属性在每个对象中都有一份,不会引起共享错误,getName和setName方法是用闭包形式访问name变量,这样避免了外部环境对Person的name变量的访问,只能通过函数对Person的name变量访问;

function Person(name){
this.getName = function(){
return name;
};
this.setName = function(value){
name = value;
};
}
var person = new Person('Lyn');
document.write(person.getName()+"<br>"); //Lyn
person.setName('Vergil');
document.write(person.getName()+"<br>"); //Vergil
//构造函数模式实现私有变量(通过闭包实现)
function Person(nameStr){
var name = nameStr;//私有变量
this.age = 15;//公有变量
this.getName = function(){
return name;
};
this.setName = function(value){
name = value;
};
this.getInfo = function(){
document.write(name + " " +this.age + "<br //Lyn 15>");
};
}
var p1 = new Person('Lyn');
var p2 = new Person('Vergil');
p1.getInfo(); //Lyn 15
p2.getInfo(); //Vergil 15
p1.setName('VergiLyn');
p1.getInfo(); //VergiLyn 15
p2.getInfo(); //Vergil 15

问题: 每次调用时都会创建函数对象,耗费资源,函数不可以共享。

2. 静态变量 (其实就是单例)

//静态私有变量
(function() {
var name = "NULL";//静态私有,被所有实例所共享
//js中不加var其实就是定义全局变量
Person = function(value) { //默认为全局变量了 ,可以被外部访问
name = value;
};
Person.prototype.getName = function() {
return name;
};
Person.prototype.setName = function(value) {
name = value;
};
})(); var person1 = new Person("Lyn");
document.write(person1.getName()+ "," + name+"<br>"); //"Lyn",""
person1.setName("Dante");
document.write(person1.getName()+ "," + name +"<br>"); //"Dante","" var person2 = new Person("Vergil");
document.write(person1.getName()+","+name+"<br>"); //"Vergil",""
document.write(person2.getName()+","+name+"<br>"); //"Vergil",""
document.write(sss); //error:sss undefined

注意:可以访问到name,但值并不是想象中的Lyn、Dante,也不是初始值"NULL"或者undefined。

忘记当初这js在哪测试的了,但我在写的时候去w3s和runoob测试了下,貌似结果不一样。

四、 Js中的true/false

false:undefined、null、false、""、0

typeof undefined // undefined

typeof null // object

null === undefined // false

null == undefined // true

五、 Js中的 typeof

typeof 一般只能返回如下几个结果:

number,boolean,string,function,object,undefined

ex:

    typeof "John" // 返回 string

    typeof 3.14 // 返回 number

    typeof false // 返回 boolean

    typeof [1,2,3,4] // 返回 object

    typeof {name:'John', age:34} // 返回 object

六、 Js中的 === 、==

// ===:类型 和 值 全相等;

// ==:只比较值相等;

null === undefined // false

null == undefined // true

var o = new Object("s"); //object

var s = "s"; //string

/** 注意Jquery提供的方法的趋避 */

document.write($.type(o) + "<br>");// string

document.write((typeof o ) + "<br>");// object

document.write($.type(s) + "<br>");// string

document.write((typeof s ) + "<br>");// string

document.write((o == s) + "<br>"); // true

document.write((o === s) + "<br>"); // false

七、 Js中的call / apply

call / apply的作用是一样的,都是js内置。

区别: 参数形式不一样;

*.call(obj,arg1...)

*.apply(obj,argArray)

作用:

Ex:

        var temp = new TempObj();

        var lyn = new LynObj(1,"vergilyn");

temp.tempMethod(lyn,arg1,arg2)

TempObj()中存在方法tempMethod(arg1,arg2)

LynObj()中不存在,现在用LynObj对象的this去调用TempObj的tempMethod()方法。

即,temp内部的this指针不指向temp而是lyn。

八、 重要:js中的prototype

函数运行时会先去本体的函数中去找,如果找到则运行,找不到则去prototype中寻找函数。(或者可以理解为prototype不会克隆同名函数)

访问顺序,先 本体 -> 原型链prototype ;当在本体找到同名时,就调用了,不会再去寻找prototype的了。

var LynObj = function(id,name){
this.name = name;
this.id = id;
this.show=function(){
alert("本体中同名的show():"+this.name);
}
}
//LynObj的原型 要写在 new LynObj()之前
LynObj.prototype={
age:24,
id:-1,
show:function(){}, //本体中有,不会调用此方法
add:function(a1,a2){
alert("add: " + a1 + " + " + a2 +" = " + (a1+a2));
}
};
var lyn = new LynObj(1,"vergilyn");
lyn.show(); //本体中的同名show():vergilyn
alert(lyn.age); //
alert(lyn.id); //1,对象本身的,不是prototype中的
lyn.add(2,4); //add: 2 + 4 = 6

问题:  1、 如果想调用prototype中的同名方法, 以上写法是不可以的。

解决:

var TempObj = function(){  //为了能调用prototype中的全部属性/方法
this.age = 24;
this.name = "dante";
this.show = function(){
alert("prototype中同名的show():"+this.name);
},
this.add = function(a1,a2){
alert("add: " + a1 + " + " + a2 +" = " + (a1+a2));
}
};
LynObj.prototype= new TempObj(); var temp = new TempObj()
var lyn = new LynObj(1,"vergilyn");
lyn.show(); //本体中的同名show():vergilyn
alert(lyn.age); //
alert(lyn.name);//vergilyn
lyn.add(2,4); //add: 2 + 4 = 6
temp.show.call(lyn);//prototype中同名的show():vergilyn /* call 或者 apply 是js内置; 把temp中的this改为lyn对象,调用show()
* 区别: call(obj,arg1...), apply(obj,argArrays)
*/

九、 JS中的for-in / in, 形式 for(name in obj) / name in obj

for-in循环遍历对象/数组,name表示对象的属性/数组的下标。

in判断name是否是obj的直接属性。返回true/false

注:in判断的是直接属性,见ex

var obj = {"a1":{"b1":"b1","b2":"b2"},"a2":"a2","a3":"a3"};
for(name in obj){
document.write(name + ":" + obj[name] + "<br>");
// a1:[Object] a2:a2 a3:a3
} var arr = [1,3,5];
for(index in arr){
document.write(index + ":" + arr[index] + "<br>");
//0:1 1:3 2:5
}
document.write(("b1" in obj) + "<br>"); // false
document.write(("b1" in obj.a1) + "<br>"); // true document.write(("a3" in obj) + "<br>"); // true
document.write(("a4" in obj) + "<br>"); // false // "1" / 1 都表示下标 js的2中调用 obj.name 等价于 obj[name]
document.write(("1" in arr) + "<br>"); // true
document.write((1 in arr) + "<br>"); // true

十、 Jquery的扩展extend

1、 jQuery.extend: jQuery类的 类方法;对jQuery类扩展, 只需 jQuery.extend(...);

/** 为jQuery类扩展的一些类方法。Jquery部分源码 */
jQuery.extend({
expando:"jQuery"+(version+Math.random()).replace( /\D/g, "" ),
isFunction: function( obj ) {
return jQuery.type( obj ) === "function";
},
isEmptyObject: function( obj ) { //判断是不是empty对象,
var name; // name = undefined
for ( name in obj ) {return false;}
return true;
}
)}

2、 jQuery.fn.extend: 因为 jQuery.fn = jQuery.prototype; 所以定义了jQuery的对象方法; 对jQuery对象扩展,只需 jQuery.fn.extend(...);

jQuery.fn.extend( {
filter: function( selector ) {
return this.pushStack( winnow( this, selector || [], false ) );
},
not: function( selector ) {
return this.pushStack( winnow( this, selector || [], true ) );
}
)}

特别

1. 根据实际的参数,判断是对jQuery的扩展(不管是类/对象),还是这是个工具类。

2. 区分深复制/浅复制的区别。

深复制:会递归处理对象中的对象。

浅复制:(可理解为)把对象中的对象当作是属性。

// jQuery-1.12.3 sourcecode:
jQuery.extend = jQuery.fn.extend = function() {
var src, copyIsArray, copy, name, options, clone,
target = arguments[ 0 ] || {}, //arguments js函数内置属性, 表示函数实际接收到的参数。类似数组,实质不是数组
i = 1,
length = arguments.length,
deep = false; //是否深复制 // Handle a deep copy situation
// Lyn:判断深复制情况 ; arguments[0] true深复制 false浅复制
/** 深复制 浅复制 区别: 深复制会递归处理复杂对象
* ex:
* var dest={};
* var result=$.extend( true/false, dest,
{ name: "John", location: {city: "Boston",county:"USA"} },
{ last: "Resig", location: {state: "MA",county:"China"} } ); * 深复制: dest = {name:"John",last:"Resig",
* location:{city:"Boston",state:"MA",county:"China"}}
*
* 浅复制: dest = {name:"John",last:"Resig",
* location:{state:"MA",county:"China"}}
*
*/
if ( typeof target === "boolean" ) {
deep = target;
target = arguments[ i ] || {};//i默认1
i++;
} // Handle case when target is a string or something (possible in deep copy)
// 当target不是object 或者 function 时,设置成{} 空内容的对象
if ( typeof target !== "object" && !jQuery.isFunction( target ) ) {
target = {};
} // 判断是不是对jQuery自身进行扩展。
// jQuery.extend() : 扩展jQuery类
// jQuery.fn.extend(): 扩展jQuery对象
if ( i === length ) {
target = this; //this指 jQuery(类) 或者 jQuery.fn(jQuery实际的对象);所以,此if表示判断对jQuery自身的扩展(类/对象)
i--;
} for( ; i < length; i++ ) {//因为数组循环,所以arguments后面的值覆盖之前的 // Only deal with non-null/undefined values
if ( ( options = arguments[ i ] ) != null ) {
//同时赋值临时变量options
// Extend the base object ****核心的继承逻辑 for循环****
for ( name in options ) {
src = target[ name ]; //可以理解为 json的 target.name
copy = options[ name ];
// Prevent never-ending loop 防止无限循环
if ( target === copy ) {
//目标对象和要拷贝的对象 恒相等,就(不复制)执行下一个循环
continue;
}
//Recurse if we're merging plain objects or arrays递归如果我们合并对象/数组
if ( deep && copy
&& ( jQuery.isPlainObject(copy)
|| (copyIsArray = jQuery.isArray(copy))
//同时赋值临时变量copyIsArray
)
) { //深复制 用递归处理合并的如果是 对象 或 数组 if ( copyIsArray ) {
copyIsArray = false;
clone = src && jQuery.isArray( src ) ? src : []; } else {
clone = src && jQuery.isPlainObject( src ) ? src : {};
} // Never move original objects, clone them 从不移动原始对象, 把新的克隆进去
// Lyn: 递归处理 对象 或 数组
target[ name ] = jQuery.extend( deep, clone, copy ); // Don't bring in undefined values 不增加一个undefined的值
} else if ( copy !== undefined ) { //浅复制
target[ name ] = copy;
}
}
}
}
return target;//返回自定义的目标对象,
// 注:因为target = arguments[0/1]所以参数0/1如果是对象,其对象结构会被改变
// 或者 为了扩展jQuery,Jquery对象被改变
};

【JavaScript】JS总结 – 乱的更多相关文章

  1. javascript(js)小数精度丢失的解决方案

    原因:js按照2进制来处理小数的加减乘除,在arg1的基础上 将arg2的精度进行扩展或逆扩展匹配,所以会出现如下情况. javascript(js)的小数点加减乘除问题,是一个js的bug如0.3* ...

  2. 【转】关于URL编码/javascript/js url 编码/url的三个js编码函数

    来源:http://www.cnblogs.com/huzi007/p/4174519.html 关于URL编码/javascript/js url 编码/url的三个js编码函数escape(),e ...

  3. paip.java 以及JavaScript (js) 的关系以及区别

    paip.java 以及JavaScript (js) 的关系以及区别 作者Attilax  艾龙,  EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:http:// ...

  4. 关于URL编码/javascript/js url 编码/url的三个js编码函数

    关于URL编码/javascript/js url 编码/url的三个js编码函数escape(),encodeURI(),encodeURIComponent() 本文为您讲述关于js(javasc ...

  5. JavaScript js无间断滚动效果 scrollLeft方法 使用模板

    JavaScript js无间断滚动效果 scrollLeft方法 使用模板 <!DOCTYPE HTML><html><head><meta charset ...

  6. JavaScript(js)/上

    JavaScript(js) ECMA-----定义的基础语法 DOM------document  object  model BOM------Browser  object  model Jav ...

  7. 【HANA系列】SAP HANA XS使用JavaScript(JS)调用存储过程(Procedures)

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[HANA系列]SAP HANA XS使用Jav ...

  8. Atitit. Java script 多重多重catch语句的实现and Javascript js 异常机制

    Atitit. Java script 多重多重catch语句的实现and Javascript js 异常机制 1. 语法错误(ERROR)和运行期错误(Exception) 1 2. 错误类型判断 ...

  9. atitit.javascript js 上传文件的本地预览

    atitit.javascript js 上传文件的本地预览 1. .URL.createObjectURL  1 1.1. 吊销所有使用 URL.createObjectURL 而创建的 URL,以 ...

  10. [javascript]JS如何获取当前时间戳

    [javascript]JS如何获取当前时间戳 一.总结 一句话总结:var timestamp = Date.parse(new Date()); 结果是带三位毫秒的,再除个1000取整即可 1.j ...

随机推荐

  1. 三、Mongodb Java中的使用

    添加maven依赖 <!--mongodb 驱动--> <dependency> <groupId>org.mongodb</groupId> < ...

  2. 【阿里云IoT+YF3300】14.阿里IoT Studio打造手机端APP

    在上一篇<13.阿里云IoT Studio WEB监控界面构建>中,我们介绍了用阿里云IoT Studio(原Link Develop)可视化构建WEB界面程序.本篇文章将介绍用阿里云Io ...

  3. 【WPF学习】第四十五章 可视化对象

    前面几章介绍了处理适量适中的图形内容的最佳方法.通过使用几何图形.图画和路径,可以降低2D图形的开销.即使正在使用复杂的具有分层效果的组合形状和渐变画刷,这种方法也仍然能够正常得很好. 然而,这样设计 ...

  4. Spring ——Spring IoC容器详解(图示)

    1.1 Spring IoC容器 从昨天的例子当中我们已经知道spring IoC容器的作用,它可以容纳我们所开发的各种Bean.并且我们可以从中获取各种发布在Spring IoC容器里的Bean,并 ...

  5. linux下使用gdb对php源码调试

    title: linux下使用gdb对php源码调试 date: 2018-02-11 17:59:08 tags: --- linux下使用gdb进行php调试 调试了一些php的漏洞,记录一下大概 ...

  6. k8s系列----索引

    day1:k8s集群准备搭建和相关介绍 day2:k8spod介绍与创建 day3:k8sService介绍及创建 day4:ingress资源和ingress-controller day5:存储卷 ...

  7. Ansible 学习目录

    1. Ansible 安装 2. Ansible hosts 文件配置 3. Ansible 常用模块 4. Ansible playbook使用

  8. python 安装pyinstaller

    pip install https://github.com/pyinstaller/pyinstaller/archive/develop.tar.gz

  9. IT运维软件免费送 智和信通战疫活动火热进行中

    突如其来的“新型冠状病毒”疫情牵动了全国人民的心,这是一场与病毒抗争,为生命逆行与时间赛跑的战役.举国上下众志成城面对疫情,在线医疗.在线教学.在线办公.在线会议.电商销售成为热点.线上经济的火热给企 ...

  10. sklearn使用小贴士

    1 sklearn简介 Scikit-learn(sklearn)是机器学习中的第三方模块,封装了常用的机器学习算法,涉及回归.降维.分类以及聚类等,提供python接口. 虽然sklearn容纳的算 ...