1. 变量。 使用全局变量需注意: 1.全局变量的泛滥使用会导致变量覆盖,出现意想不到的问题。 2. 破坏代码的可移植性。 3. 使用var避免全局变量。 预解析:var的散布问题
1. 变量。
使用全局变量需注意:
1. 全局变量的泛滥使用会导致变量覆盖,出现意想不到的问题。
2. 破坏代码的可移植性。
3. 使用var避免全局变量。
预解析:var的散布问题
JavaScript中,你可以在函数的任何位置声明多个var语句,并且它们就好像是在函数顶部声明一样发挥作用,这种行为称为 hoisting(悬置/置顶解析/预解析)。
JavaScript有一个特性叫做隐式全局变量,不管一个变量有没有用过,JavaScript解释器反向遍历作用域链来查找整个变量的var声明,如果没有找到var,解释器则假定该变量是全局变量,如果该变量用于了赋值操作的话,之前如果不存在的话,解释器则会自动创建它。这就是函数内部变量不加var会被解释成全局变量的原因。
var myname = 'global';function show(){ console.log(myname);}show(); // globalfunction show2(){ console.log(myname); var myname = 'show2';}show2() // undefinedfunction show3(){ console.log(myname); var myname = 'show2'; console.log(myname);}show3() // undefined show2
2. for循环。
for(var i=0; i< myarr.length; i++){ //}
如果这是一个对象的话,每次都要去查找对象的属性,影响性能,我们可以这样写:
var i, myarr = [];for(i = myarr.length;i--;){//}
for in 遍历对象属性。如果继承了,会查找原型链,遍历到原型中的属性,这不是期望的
for(n in obj){ if(obj.hasOwnProperty(i)){ // }}
3. 命名规范。
方法名按照驼峰命名法命名,由new调用的构造方法,首字母大写,一般方法首字母小写。
变量名统一用下划线隔开单词的命名法。封装的私有方法,用下划线开头。
4. js的module模式。
基本特征:
- 模块化,可重用
- 封装了变量和function,和全局的namaspace不接触,松耦合
- 只暴露可用public的方法,其它私有方法全部隐藏。
// 实现对象的公,私封装var Man = function(){ // 可以在这里定义所有的私有属性 var name = '张三'; return { //暴露公有的接口 echo: function(){ console.log(name); } }}var m1 = new Man()m1.echo()
匿名函数的两种闭包方式
//第一种(function(){}())//第二种(function(){})()//习惯使用第一种
为闭包引入全局变量
(function($){//可以使用$访问jquery对象了}(jQuery))
上面使用了全局变量,如果我想声明全局变量呢?
var blog = (function(){ //声明一个my对象来存储定义的方法和属性,这个是闭包的局部变量,其实就是全局的blog对象 var my = {}, _name = '博客'; my.Name = _name; //给全局blog添加属性和方法 my.show = function(){ console.log(this.Name); } return my;}())blog.Name // 博客
如果我想前面如果定义了blog就继承(在原来的基础上扩展),如果没有就定义呢?
var blog = (function(my){ my.Name = '博客'; my.show = function(){ } return my;}(blog || {}))
又有问题了,我想重载blog方法呢?
//文件1.jsvar blog = { show: function(){ console.log(111); }}; //文件2.js,重载blogvar blog = (function(my){ var oldShow = my.show; my.show = function(){ oldShow(); console.log(222); }}(blog))
创建子模块
blogModule.CommentSubModule = (function () { var my = {}; // ... return my;} ());
立即调用方法的典型使用:
//给每个对象绑定一个方法,点击显示该对象的索引var elems = document.getElementsByTagName('a');for (var i = 0; i < elems.length; i++) { elems[i].addEventListener('click', function (e) { e.preventDefault(); alert('I am link #' + i); }, 'false');}//结果,所有点击都显示 I am link 10var a = document.getElementById('results').getElementsByTagName('a');for (var i = 0; i < a.length; i++){ a[i].addEventListener('click', (function(n){ return function(){ console.log(n); } }(i)), false)}
5. prototype和__proto__。
prototype和__proto__
__proto__是对象的默认私有属性,通过__proto__属性来形成原型链,查找对象的属性。
prototype 是构造器的原型。
例如:
var person = {};
这是一个对象,所以是有__proto__属性的,就是object对象。而它是没有prototype属性的。
var Person = function(name){ this.name = name;}
这是一个构造器,是有prototype属性的
Person.prototype.say = function(){ console.log(this.name);}
他们有什么联系呢?
var person = new Person('张三');
person是对象,所有应该有__proto__
实际上 person.__proto__ === Person.prototype === Object
接下来说说继承。
直接用对象实现继承
var student = { __proto__: new Person('张三同学')}student.say(); //张三同学
用构造器来继承:
var Student = function(){}Student.prototype = new Person('张三同学');var student = new Student();student.say(); //张三同学
6. 闭包。.
闭包是代码块(bar函数)和创建该代码块的上下文中数据(foo函数的作用域)的结合。
函数是“第一类”对象。这个名词意味着函数可以作为参数被传递给其他函数使用 ,接收该函数参数的函数就称为高阶函数。
function foo() { var x = 10; return function bar() { console.log(x); };} // "foo"返回的也是一个function// 并且这个返回的function可以随意使用内部的变量x var returnedFunction = foo(); // 全局变量 "x"var x = 20; // 支持返回的functionreturnedFunction(); // 结果是10而不是20
这种形式的作用域称为静态作用域。
共享静态作用域
function baz() { var x = 1; return { foo: function foo() { return ++x; }, bar: function bar() { return --x; } };} var closures = baz(); console.log( closures.foo(), // 2 closures.bar() // 1);
7. 标准的JSON格式。
之前一直以为JSON也是对象,现在才发现是一种错误的理解,json其实就是字符串的一种格式。
// 这是JSON字符串var foo = '{ "prop": "val" }'; // 这是对象字面量var bar = { "prop": "val" };var obj = JSON.parse(foo);console.log(obj.prop)var str = JSON.stringify(bar);console.log(str); // { "prop": "val" }
JSON有非常严格的语法,冒号两边的数据必须都有引号,并且必须是双引号,单引号就不行。
8. javascript的DOM
(非IE,ie的event也属于window)
Event事件。
//ie 和 非iefunction show(e){ e = e || window.event; e.preventDefault(); // 阻止默认行为 e.stopPropagation(); // 阻止事件冒泡}