上面这个url很是适合javascript初学者阅读,感谢原做者的分享javascript
A script is a series of instructions that a computer can follow to achieve a goal.html
A browser may use different parts of the script depending on how the user interacts with the web page.java
Scripts can run different sections of the code in response to the situation around them.jquery
相似于菜谱,汽车维修操做说明书。c++
js分为两类:原始类型和(值引用)和Object类型(引用类型)。在浏览器宿主环境下,JS又能够分类为:原生对象,宿主对象,浏览器扩展对象(好比ActiveXObject).原始类型和对象类型他们的区别在于原始类型是值引用,分配在栈空间中,Object类型则在栈中分配的只是变量自己,它指向一个分配在堆中的内存块。web
(3.1415).toFixed(2)express
"3.14"编程
console.dir(new Number(3.1415))数组
VM278:2 Number浏览器
一样的
"hello world".split(" ");
["hello", "world"]
上面这段代码执行时,浏览器将值直接量转换为String对象类型,故而能够调用String的split方法
Number(), String(),Boolean(),parseInt(),parseFloat(), !, !!
typeof
operator returns a string indicating the type of the unevaluated operand.typeof操做符能识别除了Null以外的标准原始类型,不能识别具体的对象类型(除了Function外)typeof(null)返回object
返回如下内容“ undefined, boolean, number, string, symbol, function, object"
typeof operand
instanceof
operator tests whether an object has in its prototype chain the prototype
property of a constructorinstanceof操做符能够识别全部的内置对象和自定义对象,可是不能识别原生初始类型的值
返回true或者false
object instanceof constructor
Object.prototype.toString.call(123); "[object Number]" Object.prototype.toString.call("this is a string"); "[object String]"
使用.constructor能够识别全部的类型(除了null,undefined外,固然即便是null,undefined,使用.constructor也能够返回他们自己!!)。其原理为:当传入原始类型时,点操做符使得js自动转换为对应的对象类型,built-in和自定义对象则会返回对象的构造函数自己。
function getConstructorName(obj){ return obj && obj.constructor && obj.constructor.toString().match(/function\s*([^(]*)/)[1]; } undefined getConstructorName(null) null getConstructorName(undefined) undefined getConstructorName([]) "Array" getConstructorName({}) "Object" getConstructorName(123) "Number" getConstructorName("string") "String"
上面经过使用obj.constructor.toString方法可以识别全部自定义对象的前提是:你需要预先执行下面的一行代码constructoFunction.prototype.constructor = constructorFunction;
当设置构造函数的prototype原型对象属性时,不能仅仅经过一条constructorFunction.prototype = { // 一个literal对象};这种方式来定义产出对象的原型,由于这么作的话,意味着constructorFunction.prototype.constructor = Object(由于obj.constructor永远指向建立本身的构造函数自己,而在这里constructorFunction.prototype对象其实是由new Object来创造的,因此constructorFunction.prototype.constructor = Object!!)。
解决或避免上面问题的最佳实践是:每次设置构造函数的prototype属性时,顺带就执行constructorFunction.prototype.constructor = constructorFunction;
下面来解释一下相关背景。
1.每个对象都有一个constructor属性包括构造函数自己,由于构造函数也是对象;
2.任何对象的constructor始终指向建立该对象的构造函数(只要检视等效的new XXXX,就知道对象的构造函数)
3.每个函数都有一个默认的属性prototype,而这个prototype属性也是一个对象,他的constructor默认指向这个函数;
4.任何函数的prototype属性对象的constructor默认就是函数自己(在不显示设置prototype的状况下)
5.obj.constructor = objConstructor.prototype.constructor这是定律,因为prototype.constructor或显式或隐式被设置为构造函数自己,固然也能够设置为其余的函数
看看下面的代码:
function Person(name) { this.name = name; } var p = new Person("ZhangSan"); console.log(p.constructor === Person); // true p的构造函数为Person,由于p是经过new Person来建立的 console.log(Person.prototype.constructor === Person); // true 任何函数的prototype属性对象的constructor默认就是函数自己。 console.log(p.constructor.prototype.constructor === Person); // true
上面是在未设置Person的prototype属性对象的状况下默认的new Person行为;下面咱们增长一行代码,即:指定Person构造函数的prototype属性,增长一个getName广泛方法:
function Person(name) { this.name = name; } Person.prototype = { //设置Person的prototype为一个literal对象,供后代继承 getName: function() { return this.name; } } var p = new Person("ZhangSan"); //因为任何对象的constructor指向建立本身的构造函数(new XXXX中的XXXX),实际由construcfunc.prototype.constructor或显式或默认来指定
console.log(p.constructor === Person); // false //obj.constructor = objConstructor.prototype.constructor这是定律 ,而这里Person.prototype的构造函数为Object, Object的prototype.constructor默认就指向Object构造函数自己,所以p.constructor === Object console.log(Person.prototype.constructor === Person); // false 实际上Person.prototype.constructor === Object console.log(p.constructor.prototype.constructor === Person); // false
解决上面的问题,只要在设置Person.prototype属性对象以后,添加一句: Person.prototype.constructor = Person便可!!
function自己是一个object,它能够被赋值给任何变量,也能够有不少自定义的属性
immediate invoked function expression(IIFE): function(){}()
method vs function: 一个method是一个对象的一个函数属性(a method is a function that is a property of an object)例如:
var console={
log:function(){}
}
console.log(“log是console的method!");
下面的方法或者属性是string对象定义的方法或者属性!
length: 这个length其实是一个属性,而不是一个方法。
indexOf
var line = "HAL: I'm sorry, Dave. I'm afraid I can't do ▶ that"; alert( line.indexOf("I'm") ); // 5 alert( line.indexOf("I'm", 6) ); // 22
slice,substr,substring函数:
var greeting = "Hello, Andrew, what's up?", name = greeting.slice(7, 13); alert(name); // Andrew
split:该函数将一个字符串使用空格符做为分割依据将每一个单词分开放到一个数组中
var arr = "apples oranges peaches bananas".split(" "); console.log(arr); // ["apples", "oranges", "peaches", ▶ "bananas"]
toLowerCase, toUpperCase
Date object有不少实用的方法可供使用
getDate,getDay,getFullYear,getHours,getMilliseconds,getMinutes,getMonth,getSeconds,getTime,getTimezoneOffset
setDate,setFullYear,setMinute,setMonth,setSeconds,setTime,setMilliseconds,setHours,
parse:能够用于讲一个字符串解析为Date object
alert( Date.parse("June 18, 1970") ); // 14529600000 alert( Date.parse("2010/11/11") ); // 1289451600000 var d = new Date(Date.parse("1995/04/25")); // Tue Apr 25 ▶ 1995 00:00:00 GMT-0400 (EST) alert(d);
join:这是和split相反的动做,它将把数组中的全部元素结合在一块儿造成一个string
alert( ["cats", "dogs", "hamsters", "fish"].join(' ') ); // "cats dogs hamsters fish" alert( "this should not have spaces".split(" ").join("_") ); // "this_should_not_have_spaces"
pop/shift:
var arr = ["cats", "dogs", "hamsters", "fish"]; console.log( arr.pop() ); // "fish" console.log( arr.shift() ); // "cats" console.log( arr ); // ["dogs", "hamsters"]
push/unshift:push将在数组的尾部增长一个item,unshift则在数组的开始增长一个item
var arr = ["Beta", "Gamma"]; arr.push("Delta"); console.log(arr); // ["Beta", "Gamma", "Delta"]; arr.unshift("Alpha"); console.log(arr); // ["Alpha", "Beta", "Gamma", "Delta"]
reverse:
alert( ["Crockford", "Resig", "Zakas"].reverse() ); ▶ // "Zakas, Resig, Crockford"
slice:有时,你但愿将你的数组slice成多个部分,这个slice就提供这个功能。包含两个参数:index of the starting element and index of the element after the last one you want to slice.
alert( ["a", "b", "c", "d", "e"].slice(2, 4) ); ▶ // ["c", "d"] alert( ["f", "g", "h", "i", "j"].slice(1) ); ▶ // ["g", "h", "i", "j"]
sort:按照字母排序:
["d", "e", "c", "a", "b"].sort(); // ["a", "b", "c", "d", ▶ "e"] [0, 5, 10, 15, 20, 25].sort();//[0, 10, 15, 20, 25, 5].
在上面对数字的排序可能并非你但愿获得的效果,一个可行的方案是sort函数传入一个函数:
var arr = [5, 2, 3, 4, 1,10,20]; arr.sort(function (a, b) { return a - b; }); console.log(arr); // [1, 2, 3, 4, 5 ,10 ,20];
javascript也提供了一个Math 对象,你虽然不能像Date对象同样二次建立对象,可是你却能够直接调用Math对象的方法
min,max,random,round,ceil,floor,pow,
alert( Math.min(9, 1, 4, 2) ); // 1 alert( Math.random() ); // 0.5938208589795977 (you'll ▶ probably get something else) alert( Math.random() * 10 ); // 6.4271276677027345 (again,▶ your mileage may vary) alert( Math.round(10.4) ); // 10 alert( Math.round(10.5) ); // 11 alert( Math.ceil(10.4) ); // 11 alert( Math.floor(10.5) ); // 10 function getRandomNumberInRange(min, max) { return Math.floor( Math.random() * (max - min + 1) + ▶ min); } alert( getRandomNumberInRange(0, 100) ); // 39; you'll ▶ probably get something different.
This是javascript预留的keyword,你能够将this想象成一个你不能控制的动态变量。this变量的值将随着你在代码的哪个地方而不断变化其值:
默认状况下,this将指向global对象。this没有一个合适的名字,可是他却有一个属性指向它本身:window.若是你看看下面这个小的代码,就有些感受了:
var my_variable = "value"; function my_function () { return "another_value" } alert( this.my_variable ); // "value" alert( this.my_function() ); // "another_value" var global = { window : global . . . }; this = global;
这意味着你能够访问你的全局变量或者函数做为window的属性,而这比用this来访问这些全局变量函数更加广泛。这依然有点搞,由于你能够访问window对象来使用global对象上的函数或属性,即便this能够指向其余的对象。甚至,你不用使用window.xx的方式调用,除非你有一个local的变量或者函数而覆盖了全局的函数或变量!
第一种改变this指针的方法是使用new 关键字:
你可能知道了javascript对象是什么(属性和函数的封装)。将相关的功能封装到一个合适的object中而且经过合适的接口来访问是一个很是很是很是基础的OOP编程模式。Classes就像一个蓝图:他们不是实际的对象,可是他们描述了一旦经过该class建立一个object,那么这个object应该具有的函数和变量。javascript是面向对象的,可是它却不用class这个概念。想法,它使用prototypes这个概念。prototypes是一些实际的对象objects,咱们可使用这些对象objects做为鲜活的建立其余对象的蓝图”对象“。
在其余语言中,好比c++,使用一个构造函数来建立新的对象。而在javascript中,构造函数是普通的函数,若是在它前面添加一个new关键字则能够建立新的对象。
好比咱们要建立truck对象,
function Truck(model) { this.num_of_tires = 4; this.kilometers = 0; this.model = model; } var my_truck = new Truck("Hercules"); console.log(my_truck);
上面的代码注意两点:首先,咱们定义全部的变量做为this对象的属性;其次,咱们没有从这个函数中返回任何东西。这两点是由于咱们计划使用new关键字来调用这个函数建立对象。注意咱们是如何使用new关键字的。它作了两件事:首先,它更改this指针指向一个新的干净的对象。很明显,咱们而后能够增长咱们定制的属性在这个函数中。第二件new干的事情是:它将this返回。如今my_truck变量将指向新的对象,这个my_truck就像咱们下面的代码同样的结果:
var my_truck = { num_of_tires : 4, kilometers : 0, model : "Hercules" }; console.log(my_truck);
这就是使用new的想法:咱们得到一个建立新对象的超级简单的方法。很明显,你若是仅仅须要一个或两个简单的对象,你不须要这么作。一般你在须要有不少功能而且但愿打包到一个对象中时,你才须要这种new的模式,或者你但愿建立一系列相似的对象时,也可使用new方法来建立对象。
第二种更改this指针的方法是call或者apply.在javascript中一切皆为对象---即使function也是对象。既然function是对象,那么他们也能够有属性和方法(property,method)。call和apply就是每个function对象的两个默认方法。
这两个方法存在的价值就是在函数中修改this指针:
function Truck (model, num_of_tires) { this.num_of_tires = num_of_tires; this.kilometers = 0; this.model = model; } var basic_vehicle = { year : 2011 }; Truck.call(basic_vehicle, "Speedio", 4); console.log(basic_vehicle);
小知识点:primitive vs reference values:你可能想,虽然咱们更改一个已知的对象,咱们会丢失那些变动,除非咱们将他们赋值给一个新的变量。若是变量是一个primitive value,那么这将是对的。然而,objects(arrays)是referrnce values:values passed by referrnce.一个primitive value(好比一个string或者number)是在计算机内存中保存的,而咱们使用一个变量来访问它。当咱们将这个变量传给一个函数时,咱们会copy那个值到一个新的内存,而将函数参数指向这个新的copy内存,而在函数中对这个copy操做,所以原始的primitive value并不会被变动。(由于内存不一样),可是当咱们使用reference value时则不一样:当咱们传递一个object或者一个array给一个function时,形式参数将指向原始object/array相同的内存。这意味着,Truck.call(basic_vehicle)中的this和函数外的basic_object中的this是彻底一个basic_object.因此没有必要作任何assign动做,由于basic_vehicle如今已经有了由Truck赋值的全部属性。若是咱们将Truck.call(basic_vehicle)的返回值付给一个变量,将会发生什么,它将会是undefined,由于Truck without new将不会返回任何东西!
在这里,咱们经过Truck函数的call方法来调用Truck函数。call的第一个参数是咱们但愿在函数中this所指向的对象。既然咱们没有使用new来调用Truck,它将不会建立任何新的对象或者返回this.这也是咱们所但愿的,由于咱们仅仅是在修改已经存在的对象,而不是从新建立一个!
在将成为this所指向的对象参数后(你能够称为函数的上下文context),咱们能够传入任何须要的参数。这些将做为参数被传入将被执行的函数。上面的例子中,第二个参数"Speedio"将被传给Truck函数做为其第一个Parameter。第三个参数6将成为Truck的第二个参数。
和call向对应,还有一种方法叫作apply.二者的区别是:apply只接受两个参数。第一个是context object,第二个是将被传入function的一个参数的数组。若是你有一个做为数组的参数,这种方法将很是有用。例如,
function Truck (model, num_of_tires) { this.num_of_tires = num_of_tires; this.kilometers = 0; this.model = model; } var basic_vehicle = { year : 2011 }, user_input = "Speedio 18"; Truck.apply(basic_vehicle, user_input.split(" ")); console.log(basic_vehicle);
还有另一种方法能够更改this的值。
var waitress = { name : "Ashley", greet: function (customer) { customer = customer || " there!"; return "Hi " + customer + " My name is " + ▶ this.name + "; what can I get you?"; } }; alert( waitress.greet("Joe") ); // Hi Joe My name is ▶ Ashley; what can I get you?
你们都知道使用new关键字来调用一个构造函数是一种古老而有用的建立对象的方法,好比下面的构造函数:
function Computer (name, ram_amount, memory_amount) { this.name = name; this.RAM = ram_amount; // in GBs this.space = memory_amount; // in MBs }
上面是一个普通的构造函数,若是咱们使用new Computer("MacBook", 2, 250000)调用的话,咱们将建立一个Computer对象。注意:Computer并非全部computer对象的prototype(或者blueprint),Computer仅仅是这些computer对象的构造函数constructor,也就是构造产出对象own Property和own Method!!!!.
若是咱们但愿给上述computer对象增长一个函数,好比保存文件的能力函数将会发生什么?你可能这么作:
function Computer (name, ram_amount, memory_amount) { this.name = name; this.RAM = ram_amount; this.space = memory_amount; this.files = []; this.store_file = function (filename, filesize) { this.files.push(filename); this.space -= filesize; }; }
上面的方法看似无伤大雅,可是这里存在一个问题。你不该该在你的constructor function中建立function,由于每次你建立一个新的对象copy时,你将会建立那个function的新的copy,而这将占用内存。关键是:没有必要这样作,由于咱们能够仅仅保存那个function的一个copy,而该copy将为全部的Computer object服务。这之因此工做,是由于咱们在构造函数中使用this来引用了对象自己。
咱们须要作的是一种方法用于将每一份Computer对象指向一个store_file函数的方法。咱们迄今所讨论的方法是有效的,由于function是一个method,因此this指向一个对象。咱们能够这样作--而且只须要一个函数--而使用Computer构造函数的prototype属性:这意味着使用new Computer建立对象时,除了Computer构造函数own property/own method之外,还有一个隐形的__proto__原型链生成以便供继承使用!
Computer.prototype.store_file = function (filename, filesize) { this.files.push(filename); //this指的是new Computer的返回对象 this.space -= filesize; };
记住:function自己也是object哦,因此他们能够有属性的,在上面这个代码片断中,咱们访问了Computer构造函数的prototype属性,而该属性的值其实是一个object,该对象是全部Computer objects用于inherit的祖。这意味着:当你运行: my_computer.store_file("image.jpg",26)时,js引擎发现my_computer自己并无一个叫作store_file的method,因此js引擎会继续查看my_computer的prototype object(Computer.prototype来指示)(经过my_computer.__proto__来寻址),若是在prototype中发现这个方法则调用它,若是没有发现,则继续向prototype chain中继续向上搜索,直到最上层Object.prototype---Object是javascript中的全部对象的父亲。
在这个使用new+constructor来建立新的对象的案例中,有两点须要说明:
1. 构造函数自己建立一个对象(denoted by this inside the function);在这个函数中,咱们对该对象的属性进行赋值操做;
2. 每个使用指定constructor建立的任何一个对象的prototype或者说parent object都保存在ConstructorFunction.prototype(注意构造函数自己也是一个对象)里。全部prototype/parent对象的属性或者方法均可以从"child"object中来访问(机制是由js的prototype chain检索来实现的)
这就是为何被称为"Prototypal Inheritance";每个从相同的构造函数建立的对象都继承于相同的prototype。很重要的一点是:若是一个给定的child object有一个它本身的属性,好比说my_obj.name,那么prototype不会被检索该属性。同时,若是你修改一个child object的属性或者方法,你只修改了那个对象自己,并不会影响到prototype object。
如下为例:
function Product(name) { if (name) { this.name = name; } } Product.prototype.name = "To be announced"; //提供默认的name,若是new Product时传入name则覆盖这个原型上的默认值 Product.prototype.rating = 3; var ipad = new Product("iPad"); alert( ipad.name ); // "iPad"; alert( ipad.rating ); // 3
// ipad from above
ipad.rating = 4;
ipad.rating; // 4
Product.prototype.rating; // 3
这里咱们建立了一个简单的Product对象,你能够看到name属性打印的是ipad对象自己修改事后的name,而rating属性则是来自prototype的继承(实际上,若是你在child object上修改也会覆盖掉prototype的属性)。经过修改rating这个值,咱们实际上就是在ipad对象上添加了一个rating属性,由于对象的原型对象上的属性是只读的!!,既然ipad对象本身有了rating属性,当咱们访问ipad.rating属性时,js引擎将再也不向上级prototype检索。然而,即使如此,prototype的rating属性值也没有被改变。
当一个函数没有使用" . "来调用该函数时,这个函数中的this指针是和这个函数被调用前面一行的this是指向同一个对象的
好比:
var joe={ firstName: 'joe', lastName: 'will', fullName: function() { return this.firstName + ' ' + this.lastName; } } var fullName = joe.fullName; var firstName = 'John'; var lastName = 'papa'; console.log(fullName()); //注意因为fullName()函数被直接调用,未用.方式来引用,所以fullName函数中的this和他前面一行指向是相同的。在这里也就是global的空间,而全局空间中确实有firstName和lastName,故而输出” John papa“
另一个简单的例子,经过jquery定位到全部的"all" button,点击之后全部的answer div内容将变为button的text:
html: Mark ALL test: <button class="all">Yes</button><button class="all">No</button> <div class="answer">?</div> <div class="answer">?</div> <div class="answer">?</div> javascript: $(function(){ $('.all').click(function(){ //在这个context时,this是指$('.all')即button var that = this; $('.answer').each(function(){
//这里this是指各个有.answer类的单个div $(this).text($(that).text()); }); }); });
迄今为止,咱们讨论除了Objects外的全部type的方法,之因此这么安排是由于:
1.我但愿保持全部object-related资料在一个集中的地方;
2.大多数你可使用的methods就是你本身建立的那些方法
然而,对于object对象自己也有一些built-in的方法。既然你建立的任何对象都是一个Object(即:从Object.prototype来继承的),那么这些方法都是随时可用的:
function Person(name) { this.name = name; } Person.prototype.legs = 2; var person = new Person("Joe"), prop; for (prop in person) { console.log(prop + ": " + person[prop]); } // in console: // name : Joe // legs: 2
在这里,若是你的对象是从有着属性的prototype继承过来的,那么那些属性自己也会被loop检索到。这可能会打印出你不但愿看到的结果(好比从prototype中继承出来的leg)。在这种状况下,对象可使用一个实用的方法hasOwnProperty来决定一个给定的property是否属于object自己仍是它的prototype.
function Person(name) { this.name = name; } Person.prototype.legs = 2; var person = new Person("Joe"), prop; for (prop in person) { if (person.hasOwnProperty(prop)) { console.log(prop + ": " + person[prop]); } } // console: // name: Joe
每个object都有一个toString方法。这个方法在object在任何地方将被打印时调用;它的做用是转换对象为一个字符串。不一样的built-in types将作不一样的事情:strings明显不会改变;数字将会成为数字的字符串;dates将格式化为date strings。可是通常的object将会怎样呢?
var o = { name : "Andrew" }; alert( o.toString()); // "[object Object]"
上述代码实际上毫无用处,只是告诉你它是一个object。如何解决这个问题呢?你能够定义你本身的toString函数来覆盖prototype中的这个函数
var person = { name : "Joe", age : 30, occupation: "Web Developer", toString : function () { return this.name + " | " + this.occupation; } }; alert( person.toString() ); // "Joe | Web Developer"
valueOf:
该函数将返回一个primitive value以便表明你的对象。好比:
var account = { holder : "Andrew", balance : 100, valueOf : function () { return this.balance; } }; alert( account + 10 ); // 110
var Human = { arms: 2, legs: 2, walk: function() { console.log("Walking"); } } << {"arms": 2, "legs": 2, "walk": function () ➥{ console.log("Walking"); }} lois = Object.create(Human); << {"arms": 2, "legs": 2, "walk": function () ➥{ console.log("Walking"); }}
closure是javascript最重要的一个功能之一。若是你熟悉其余的编程语言(特别是oop的语言,好比c++),你必定知道private variable(私有变量)这个概念。一个私有变量就是一个仅仅被对象的方法可以访问而不能在对象以外直接访问的变量。Javascript自己并无这个功能,可是咱们可使用closure来"make"private variables。记住两点关于贡献于closure的javascript特性:
1.everyting is an object, even functions.这意味着咱们能够从一个函数返回一个函数
2.Anonymous,self-invoking functions是没有名字的当即运行而一般只运行一次的函数
如今咱们使用这两个概念来建立一个closure。首先看看一般的javascript代码:
var secretNumber = 1024; function revealSecret(password) { if (password === "please") { return secretNumber++; } return 0; }
上面这段代码对你来讲是很普通的。咱们有一个叫作secretNumber的变量和一个若是密码正确返回加1的函数。在这里,secretNumber变量自己没有任何秘密可言,他是一个任何函数都能访问的全局变量。为了增长私密性,为何咱们不将它放到函数内部呢?这样咱们从函数外面就将不能访问这个变量了!
不过注意了,咱们不能那样作哦,由于若是那样,每次咱们调用那个函数,js引擎都将reset setcretNumber变量到1024!怎么作呢?Closure能够完成上面的场景!
var revealSecret = (function () { var secretNumber = 1024; return function (password) { if (password === "please") { return secretNumber++; } return 0; }; }()); alert( revealSecret("please") ); // 1024 alert( revealSecret("please") ); // 1025
注意revealSecret自己被赋予一个anonumous self-invoking function的返回值。既然那个匿名函数当即运行,revealSecret就将被赋予该函数的返回值。在这个例子中,它又是一个函数。下面的事实使人印象深入:内部函数(被返回的函数)自己引用了secretNunber变量从它的"parent"function's scope.即便匿名函数已经返回,inner function依然可以访问到这个变量。那就是closure:an inner function having access to the scope of it's parent function, even after the parent function has returned!!!这种方法,secretNUmber仅仅被初始化一次,它能够在每次内部函数调用时加1,而任何其余人不能访问它,由于它被匿名函数的scope所保护。总的来讲:closure是暴露从函数外来访问一个函数的scope的有限控制(closure is the concept of exposing limited control of a function's scope outside the function.)
这种closure在建立模块时也很是有用:
var a_module = (function () { var private_variable = "some value"; function private_function () { // some code; } return { public_property : "something" // etc : " ... " }; }());
这就是module pattern:在一个anonymous selft-invoking function中,咱们建立没法在匿名函数外访问的变量和方法。而后,咱们返回一个对象,这个对象包含public属性和可以访问匿名函数闭包里面的私有变量或者方法的公共方法。经过这种方式,那些没必要暴露的信息被屏蔽,而咱们只须要暴露共有的函数或者变量。
有两种错误:一种是当你写代码时犯的错误,好比语法错误或者类型错误,另外一种是没法预知的错误,好比用户的输入错误或者missing feature in the js engine.虽然js引擎一般默默地处理晓得错误,好比忘记了分号,一些大的严重错误js会抛出异常。固然,咱们也能够主动抛出咱们本身的错误异常。
try { // code that might cause an error here } catch (e) { // deal with the error here }
咱们将可能产生错误的代码封装在try块中。若是咱们不这样作,js引擎会处理那个错误,这可能意味着中止执行你的代码而且可能向用户显示错误:而这可能并非咱们想要的。若是一个错误被抛出,error object将被传递到catch block。在catch代码块中,你能够处理这个错误。
在error对象中,不一样的web浏览器包含不一样的属性。他们都会包含error name和error message.Firefox也会包含文件名和文件行。Chrome包含一个stack trace.也有一些其余的东西,可是主要的就是name和message.
function make_coffee(requested_size) { var sizes = ["large", "medium", "small"], coffee; if (sizes.indexOf(requested_size) < 0) { throw new Error("We don't offer that size"); } coffee = { size: required_size, added: ["sugar", ▶ "sugar", "cream" ] }; return coffee; } try { make_coffee("extra large"); } catch (e) { console.log(e.message); }
什么是event?
event,简单地说,就是在DOM中的元素上发生的事件,好比:
1.the page loaded;2.an element was clicked;3.the mouse moved over an element;4.when something like this happnes, you may often want to do something.好比,当page loaded,运行一段js代码,或者当元素被clicked时,执行这个函数。。。
常见的event事件有:click,mouseover,mouseout,keypress,load,submit
正如你所看到的事件能够分为两类:一类为用户的行为所致使的事件,一类是浏览器的行为所致使的事件。上面的简单列表中:用户执行click,mouseover,out和keypress事件;浏览器fires the load event when the page has finished loading, and the submit event when the user clicks a submit button(so it is almost a user-performed events)
An event is fired on a given DOM element.这意味着咱们能够wireup一个event handler(或者event listener)to a given element.一个event handler是一个当一个给定事件发生时须要执行的函数。好比下面的代码:
// <div id="some_button"> Click Me! </div> var btn = document.getElementById("some_button"); function welcome_user(evt) { alert("Hello there!"); } btn.addEventListener("click", welcome_user, false);
在event中有一个概念bubbling and capturing:
<div> <span> Click Here! </span> </div>
看上面的代码,若是咱们点击span,由于span在div元素内,因此当咱们点击span时,div元素也将被点击。因此两个元素div和span豆浆有一个click事件被触发。若是两个元素都有eventhandler侦听,那么豆浆被调用。问题是:谁先被执行?这就是capturing和bubbling的背景了。DOM标准说事件应该首先capture随后bubble. Capture阶段是当事件从最高级别的元素开始向下扩散。在这里,click handler of div将被先执行。一旦event到了最底部,或者最里面,event将被bubble。Bubble阶段将从最底部不断向上冒泡。咱们再回到addEventListener的第三个参数是用于指定是否在capture phase来处理。因为IE9以前不支持capturing,那么一般false是安全的(bubbling)。