作用域 在 JavaScript 中, 作用域(scope,或译有效范围)就是变量和函数的可访问范围,即作用域控制着变量和函数的可见性和生命周期。在ES5中没有块级作用域的概念。
全局作用域(Global Scope):最外层函数定义的变量拥有全局作用域,即对任何内部函数来说,都是可以访问的。 局部作用域(Local Scope):和全局作用域相反,局部作用域一般只在固定的代码片段内可访问到,而对于函数外部是无法访问的,最常见的例如函数内部。 如果局部作用域的“预解析空间”(AO-活动对象(Active object))没有找到,那么代码会从上一级的作用域寻找,上级作用域不能在下级作用域寻找。 注意事项:
需要注意的是,函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明了一个全局变量! 只要函数内定义了一个局部变量,函数在解析的时候都会将这个变量“提前声明” 作用域链(Scope Chain) 通俗地讲,当声明一个函数时,局部作用域一级一级向上包起来,就是作用域链。当执行函数时,总是先从函数内部找寻局部变量;如果内部找不到(函数的局部作用域没有),则会向创建函数的作用域(声明函数的作用域)寻找,依次向上。
执行环境(execution context):JavaScript为每一个执行环境关联了一个变量对象。环境中定义的所有变量和函数都保存在这个对象中。 闭包 可以读取自身函数外部的变量(沿着作用域链寻找) 让这些外部变量始终保存在内存中 js函数内的变量值不是在编译的时候就确定的,而是等在运行时期再去寻找的。
模块 必须有外部的封闭函数,该函数至少被调用一次(每次调用都会创建一个新的模块实例)。 封闭函数必须返回至少一个内部函数,这样内部函数才能在私有作用域中形成闭包,并且可以访问或者修改其他私有的状态。 一个具有函数属性的对象本身并不是真正的模块。从方便观察的角度看,一个从函数调用所返回的,只有数据属性而没有闭包函数的对象并不是真正的模块。
this对象 “谁调用指向谁”
this对象是在运行时基于函数的执行环境绑定的:在全局函数中,this等于window,而当函数被作为某个对象调用时,this等于那个对象。不过,匿名函数具有全局性,因此this对象同常指向window。
严格模式 消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为 消除代码运行的一些不安全之处,保证代码运行的安全 为未来新版本的Javascript做好铺垫 在使用严格模式的时候在全局或函数的第一条语句需定义为: ‘use strict’; 如果浏览器不支持, 只解析为一条简单的语句, 没有任何副作用
主要内容:
必须用var声明变量(混杂模式中可以直接使用变量而不定义,但是这种做法会对后期造成很大的麻烦) 创建eval作用域 禁止this指向window 对象不能用重名的属性 函数不能有重名的形参 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 'use strict'; //在全局或函数内第一行书写 //1.变量必须使用var 定义 否则报错 str="xxx"; //2.函数内的this指向不再是window function Person(name,age) { console.log(this);//undefined this.name=name;//相当于设置undefined.name =name 报错 this.age=age; } //3.让eval有自己的作用域 var str =123; eval('var str=456;alert(str)');//456 alert(str);//123 //4.对象不能用重名属性 var obj ={ username:'kobe', username:'zs' } console.log(obj);//运行时没有报错,不过编辑器内有提示 最好别这么写就是了
json对象 JSON.stringify(obj/arr)js对象(数组)转换为json对象(数组) JSON.parse(json)json对象(数组)转换为js对象(数组)
1 2 3 4 5 var obj={username:"mike"}; obj=JSON.stringify(obj); console.log(typeof obj); //json对象和数组,不要说json字符串 //json是一种传输数据的格式,还有xml。
object对象方法扩展 ES5给Object扩展了好一些静态方法, 常用的2个:
Object.create(prototype[, descriptors]) : 创建一个新的对象 以指定对象(prototype)为原型创建新的对象 指定新的属性, 并对属性进行描述 value : 指定值 writable : 标识当前属性值是否是可修改的, 默认为true get : 用来得到当前属性值的回调函数 set : 用来监视当前属性值变化的回调函数 1 2 3 4 var obj={username:"damu",age:30}; var obj1={}; obj1=Object.create(obj); //Object是obj1上一级的构造函数,调用他所具有的函数creat console.log(obj1); //也就是obj1可以继承obj的属性username和age
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 var obj={username:"damu",age:30}; var obj1={}; obj1=Object.create(obj,{ sex:{ value:"男", writable:true,//有一个writable属性:标识当前属性值是否是可以修改的,默认为false configurable:true,//有一个属性configurable:标识当前属性是否可以被删除 enumerable:true //有一个属性enumerable:标识当前属性是否能用for in枚举 默认为false } } //对当前扩展属性的描述 }); //使用create给obj1添加扩展属性 console.log(obj1.sex); obj1.sex="女" console.log(obj1.sex); delete obj1.sex;//规定不能直接删掉,有一个属性configurable:标识当前属性是否可以被删除,默认为false console.log(obj1.sex); for(var i in obj1){ console.log(i)//for in 找不到obj1使用create扩展出来的属性 //有一个属性enumerable:标识当前属性是否能用for in枚举 默认为false }
Object.defineProperties(object,descriptors) 作用:为指定object对象定义扩展多个属性 get:用来获取当前属性值的回调函数 set:修改当前属性值的触发的回调函数,并且实参即为修改后的值 存取器属性:setter,getter一个用来存值一个用来取值 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 var obj2={firstName:"kobe",lastName:"bryant"}; Object.defineProperties(obj2,{ fullName:{ get:function () {//使用get来获取扩展属性的值 return this.firstName+" "+this.lastName//fullName想要设置的值 }, set:function (data) {//监听扩展属性,当扩展属性发生变化时自动调用后会将变化的值作为实参注入到set函数。 console.log("set()",data); var names=data.split(" "); this.firstName=names[0]; this.lastName=names[1]; } }//创建一个配置对象 }) console.log(obj2.fullName) obj2.fullName="haha heih"; console.log(obj2.fullName) //get方法什么时候调用? 获取扩展属性值的时候,get方法自动调用 //对象本身的两个方法: //get propertyName(){} //set propertyName(){} var objj={ age:15, tall:180, get all(){ return this.age+" "+this.tall; }, set all(data){ console.log("set()",data); var names=data.split(" "); this.age=names[0]; this.tall=names[1]; } } console.log(objj); objj.all="13 189"; console.log(objj);
数组扩展 Array.prototype.indexOf(value):得到值在数组中的第一个下标,输入第一个3的下标 Array.prototype.lastIndexOf(value):得到值在数组中的最后一个下标 Array.prototype.forEach(function(item,index){}):遍历数组 Array.prototype.map(function(item,index){}):遍历数组返回一个新的数组,返回加工之后的值 Array.prototype.filter(function(item,index){}):遍历过滤出一个新的子数组,返回条件为true的值 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 var arr=[2,3,5,1,4,6,3]; console.log(arr.indexOf(3)); //输出第一个6的下标 console.log(arr.lastIndexOf(3)); //输出最后一个6的下标 arr.forEach(function(item,index){ console.log(item+" "+index) //输出所有元素的值和下标 }) var arr1=arr.map(function(item,index){ return item+10; }); console.log(arr1); //根据arr产生一个新数组,要求每个元素比原来大10 var arr2=arr.filter(function(item,index){ return item > 4; }) console.log(arr2); //根据arr产生一个新数组,返回的每个元素都要大于4
bind()、call()、apply()的区别 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 var obj={username:"kobe"}; function foo(data){ console.log(this,data) } // foo(); //自调用时this指向的是window,使this指向我们定义的obj foo.call(obj); foo.apply(obj); //call和apply在不传参的情况下使用方式是一样的 //区别 function foo(data){ console.log(this,data) } foo.call(obj,33); //直接传入参数 foo.apply(obj,[33]); //传入数据必须写在数组里 //bind var bar=foo.bind(obj,33);//绑定完this有一个返回值,不会立即调用当前函数而是将函数返回,通常用来指定回调函数的this。用bar来接收返回的函数然后执行 bar(); // 也可写成foo.bind(obj,33)()
任何值得做的事就值得把它做好。- Whatever is worth doing is worth doing well.