JavaScript知识点(一)包括 数据类型、表达式和运算符、语句、对象、数组。
一、数据类型
1) js中6种数据类型:弱类型特性 5种原始类型:number(数字)、string(字符串)、boolean(布尔值)、null 、undefined 1种对象类型:object对象(函数function 数组array 日期Date等)
2)数字转换字符串可以的+"",字符串转换数字可以-0
例:var num = 32;
num = "this is a string"
32 + 32 //结果为64
"32" + 32 //结果为"3232" (会被认为字符串拼接)
"32" - 32 //结果为0 (被认为数字相减)
3)等于与严格等于:
严格等于===:
如果两边类型不同,直接返回false
类型相同:
null===null
undefined===undefined
NaN≠NaN (NaN不等于任何,包括本身)
new object≠new object (js中对象是通过引用来比较而不是通过值比较)
等于==:
若类型相同,同===
若类型不同,尝试类型转换和比较:
如:
null==undefined相等
number==string 会尝试把字符串转换为数字 1=="1.0"//true
boolean==? 会将boolean转换为数字,true转成1,false转成0 1==true//true
object==number|string会尝试把对象转为基本类型 new string("hi")=="hi"//true
其他情况:false
例: "1.23"==1.23
0==false
new Object()==new Object()
[1,2]==[1,2]
4)javascript包装对象
javascrpt隐藏机制:当把一个基本类型以对象的形式去使用的时候,javascript会将其转换为包装类型对象,相当于new一个string .
但是当操作完毕后这个临时包装对象就会被销毁,无法调用。
例:
var a="string"; a.length;//6 a.t=3; alert(a.t);//undefined 当尝试以对象的方式使用一个string/number/boolean基本类型的时候,
比如访问这个字符串的length属性或增加一个属性,JavaScript只能把这个基本类型转换成包装类型对象。
当设置完成后,这个临时对象会被销毁掉。所以再次访问该属性,就是undefined。
演示效果:
二、表达式和运算符
1)表达式:
1. 原始表达式 //常量、直接量、关键字、变量 3.14、"test"、null、i、k、j 2. 数组、对象的初始化表达式 //[1,2]、{x:1, y:2}
[1, 2] 等价于 new Array(1, 2); [1, , , 4] 等价于 [1, undefined, undefined , 4]
{x:1,y:2}等价于 var o=new Object(); o.x=1;o.y=2;
3. 函数表达式 //var fe = function(){}、(function(){})()
4. 属性访问表达式 //var o = {x:1}、o.x、o['x']
5. 调用表达式 //func()
6. 对象创建表达式:
var temp=new Func(1,2)//有参数,没有参数时也可以把括号直接去掉 var temp=new Object;//没有参数
2)运算符
特殊运算符的种类: 1、条件运算符 c?a:b c为true 则取a,否则取b 2、逗号运算符 a,b 例如 var s = (1,2,3),则s依次赋值,最后输出为3 3、delete运算符 delete obj.x 删除对象obj中的x属性 在IE9下,obj中必须configurable:true 才可以删除,否则无效 4、in运算符 判断obj是否有值或window里是否有变量,返回布尔值 例如 attr in json 或 'document' in window 5、instanceof 判断对象类型 {} instanceof Object // true(返回布尔值) 6、new运算符 创建一个新对象 new obj / new array ... 7、this对象 全局用指向window,函数内指向函数本身,浮动指针 8、typeof 判断对象,返回对象类型 例如 typeof 100 === 'number' // true(判断对应类型字符串) 9、void 一元的,判断所有值,返回均为undefined 一般delete 运算符可以删除对象的属性,而如果使用方法Object.defineProperty(对象,'属性',{configurable:false})处理了对象,该属性就不会被删除,反之ture就是可以被删除
三、语句
1) 以{}组成块block,常用于for循环和if判断语句中,要注意没有块级作用域,比如for循环中var i=0;写在()内和写在for循环外面是一样的;还是属于全局变量; 在函数内定义 var a=b=1;会隐式定义出全局变量b;在函数外获取不到a,为undefined,但可以获取到b,a=1,b=1解决 在ES6面试之后有了let,即开始有了块级作用域。
var声明变量:
var a=1; var a=b=1; function fuc(){ var a=b=1; } func(); console.log(typeof a)//undefined 局部变量 外部不可访问 console.log(typeof b)//number (隐式创建了全局 变量)
2)
try - catch - finally 语句: 1.使用throw 抛出的异常,需要被catch 处理,无论是否有catch 处理,都会执行finally 2.若嵌套try - catch - finally 语句,先看内层 throw 的error 是否被内层的catch处理,否则则被外层 catch 处理。 3.若内层 catch 处理时,也throw 了 error,则外层catch 仍会处理。否则,外层catch 不执行。 4.try语句如果抛出异常,则执行catch语句,否则不执行,无论有没有异常,都执行finally语句;try语句必须跟catch或finally语句中至少一个组合使用。
try catch语句的嵌套语句执行顺序: 1)如果内部嵌套的try语句抛出异常,但内部没有相配套的catch语句,先执行内部的finally语句,然后跳到最近一层的catch语句执行。 2)如果内部嵌套的try语句抛出异常,内部有相配套的catch语句,先执行此语句处理异常,再执行内部的finally语句。不会再在外部处理异常。 3)如果内部嵌套的try语句抛出异常,内部有相配套的catch语句,并且catch语句也抛出异常,如果内部的catch语句有对异常的处理,
先执行异常处理语句,然后执行内部的finally语句,最后执行离内部catch语句抛出异常最近一层的catch语句处理异常。
3)
function fun() 这个叫函数声明,会预先处理,所以调用能写到声明前面。 var fe = function(){}则不可以。
1、for in遍历的时候,顺序不确定,如果要按顺序显示,不要用for in 2、enumerable(枚举)为false时不会出现 3、for in对象属性时受原型链影响,如果原型链上有其他值,也会在for in 的时候出现。
4)严格模式
JS的严格模式: 定义和优点:严格模式是一种特殊的执行模式,它修复了部分语言上的不足(禁用with),
提供了更强的错误检查(重复属性,删除delete不可配置的属性等),并增强了安全性(在eval中使用独立作用域等); 模式的使用: (1)function func(){'use strict';}好处:向上兼容 (2)'use strict'; function func(){}指定整个js内的代码都是在严格模式下 与普通模式的区别: 在严格模式下:①不允许使用with;
②不允许未声明的变量被赋值
③arguments变为参数的静态副本,不管参数传与不传,对arguments无影响,但是对象的属性除外;
④delete参数,函数名报错
⑤delete不可配置的属性报错
⑥对象字面量重复属性名报错
⑦禁止八进制字面量
⑧eval,arguments变为关键字,不能作为变量、函数名
⑨eval变为独立作用域,其它地方不可以拿到eval的值;
四、对象
1.对象:对象中包含一系列的属性,这些属性是无序的,每个属性都有一个字符串key和对应的value; var obj ={ x:1,y:2}; obj.x;//1 obj.y;//2
2.对象构造: 除了本身被赋予的值之外,对象还有几个隐藏标签: proto:对象的对象属性prototype上的赋值,每一个对象都有一个原型[prototype] class:对象的种类,表示属于哪一个类 extensible:表示是否允许该对象继续增加新的属性 另外对象的值(如 x=1),也有对应的属性或方法,提供一些访问权限的控制 writable:是否可写 enumerable:是否能被删除 configurable:是否能够枚举 value:值 get/set:
3.创建对象的方法: 1) 对象字面量 var obj1 = { x:1 , y:2); 2) new/原型链 function foo(){} foo.prototype.z=3; var obj = new foo();
注意:给对象赋值时,并不会去查找原型链,仅在该对象内查找,有则覆盖,无则创建。
如:
1、obj.z=5;-->若给obj赋值,并不会去原型链上查找,会看obj上是否有这个值,有就能修改,没有就仅在当前对象添加值 2、delete obj.z后,通过obj.z访问到的是原型上的z;delete obj.z只能delete当前对象的属性而不会去影响到原型链
obj.z = undefined; 并不一定代表 obj 上没有z属性,可能是有,其值为undefined。 如果想继续使用原型链上的z ,
需要delete obj.z 用直接赋值法创建对象时,对象的属性可以通过hasOwnProperty和in(in会向上找到原型链)来判断是否是对象本身中的属性,还是对象自己添加的属性。
注意:对象自己添加的属性可以通过delete来删除,但不能用delete删除原型上的属性。
同时,发现一个属性值为undefined不一定是这个值未定义,也有可能是有这个属性,其属性值就是undefined
3)var obj = Object.create({x:1})
Object.create: var obj = Object.create({x:1}); Object.create()是一个系统内置的函数,其参数通常为一个对象,
该方法返回一个新创建的obj对象,并且该obj对象的原型指向这个参数对象,而参数对象原型指向Object.prototype。 并不是所有的对象都有.toString()方法,因为不是所有的对象的原型链上都有Object.prototype属性 例: var obj = Object.create(null); obj.toString // undefined
4.属性操作
1) 用for-in遍历时,原型链上的属性也会被遍历到,而且是无序遍历。 2) 属性删除用delete, prototype属性不可被删除;
var定义的变量也不可用delete删除,函数也不可以被delete掉
(经验证,不同的内核实现方式不同,在chrome下不可被delete掉,返回false,但在firefox和IE10下可以被delete掉,返回true,对于函数也是相同的结果) eval()里面用var定义的变量可以用delete删除。
3)configurable:是否可配置。getOwnPrototypeDescriptor(属性所在的对象,属性名) 4)in操作符会向原型链向上查找的,hasOwnProperty 是检测对象在排除原型链的情况下是否具有某个属性(用在for in判断过滤原型上的属性)。 5)Enumerable:是否可枚举。 6)Object.defineProperty自定义对象属性(参数:属性所在的对象,属性名,描述符对象) Object.defineProperty(obj,"price",{enumerable:false,configurable:false,value:1999})// obj.hasOwnProperty("price")//判断是否是自身属性 obj.propertyIsEnumerable("price")//判断是否可枚举 7)!=undefined就是不等于null和undefined 8)delete 可以删除对象的属性,删除不了全局变量和局部变量,隐士声明全局变量和在eval 中声明的变量可以删除
注意:
判断某个属性是否存在与某个对象中,可以通过in运算符,hasOwnProperty()和propertyIsEnumerable()方法来完成. in运算符,如果对象的自有属性或继承属性中包含这个属性,则返回true. 对象的hasOwnProperty()方法用来检测给定的名字是否是对象的自有属性. propertyIsEnumerable()是hasOwnProperty()的增强版,只有检测到时自有属性且这个属性的可枚举性为true时才能返回true.
5.get/set方法
var obj = new foo(); obj.z; //1 obj.z = 10; obj.z;// still 1 如果对象的原型链上有 z 属性,且z 属性有 get/set 方法,则不会直接在obj 上添加 z 属性,而是使用 obj的原型链上的get/set 方法。 此种情况下希望在 obj 上添加 z 属性,需要使用defineProperty()方法,此方法默认所有标签为false 若以后需要delete obj 上的z 属性,需把configurable:true
例:
val = +val; 一元操作符的使用,让传入的值转换成相应的数字,如果原来就是数字或者转换成功,则后续操作就用数字进行,如果转换失败,将返回NaN...
6.属性标签
Object.getOwnPropertyDiscriptor(obj,"x")//获取对象的属性标签 修改多个属性标签 Object.defineProperties(obj,{ title:{value:"xxx"}, name:{configurable:true} sex:{ get:function(){ return "nan" } } } );
标签属性: configurable :是否可以配置属性,可以用来设定是否能够删除 writable:设置是否可以写入,可以用来设定是否能够进行重新赋值 enumerable:设置是否可以进行枚举 value:指定默认值
7.对象标签、标签序列化
1)对象标签: [[proto]]:原型链 [[class]]:toString [[extensible]]:表示对象的属性是否可以添加。 object.preventExtensible(obj);//使obj对象不可新增属性,原属性可改、可删 Object.seal(obj);//使obj不可新增属性,原属性可改但不可删 Object.freeze(obj);//使obj不可新增属性,原属性不可更改、删除 注意,当Object.freeze(obj)后,Object.isSeal(obj)返回的也是true,也就是说,Object.isSeal(obj)返回true,其原属性也可能不可改。
2)序列化 通过全局的JSON.stringify(obj);做序列化处理 注意: 1、当你对象中有属性的值是undefined的时候,这该属性是不会出现在序列化字符串的结果里 2、当你属性的值是NaN或者Infinity时,序列化的结果是null;当你的属性值是new Date(),序列化的结果是UTC的时间格式 后端返回JSON数据,则用JSON.parse来转化;合法的JSON的属性必须用双引号引起来
五、数组
1) 创建数组、数组操作
1、JS中的数组是弱类型的 数组中可以含有不同类型的元素 数组元素甚至可以是对象 或者其他数组; 2.创建 2.1 字面量 var arr = ['ds','aa']; 2.2 new Array构造器 var arr = new Array(); var arr = new Array(10); 则表示该数组有10个空元素(只有一个值的时候表示有多少元素) var arr = new Array('a','b'); 等价于 ['a','b']; new 是可以省略的 3.数组的读写 数组元素增减 用delate可以删除元素,但是数组长度不变,其实delate之后,是设置元素的值为undefined。 arr.push(1); 在数组尾部添加元素 arr.unshift();在数组头部添加元素 delete arr[2]; 是将数组中的下标为2的元素 变成undefined 并非真正的删除 arr.pop() 删除数组的最后一个元素 arr.shift() 删除数组的第一个元素
数组的最大长度是2^23-1 delete 直接删除和直接赋值为undefined是不一样的, delete后 arr[i] in arr; --->false 赋值undefin后 arr[i] in arr; --->true
4.数组迭代 for循环 for in 遍历(定义在原型上的属性也会遍历出来) 使用hasOwnProperty可以避免将原型上的属性遍历出来
for(i in arr){ if(arr.hasOwnProperty(i)) //不会遍历出原型上的元素 }
2)二维数组、稀疏数组
1.二维数组,就是一维数组的元素是数组,所以通过一维数组下标只是找到了子数组,要想访问子数组的元素,还需要子数组的下标。
所以要想访问二维数组元素,外层数组名[外层数组下标值][字数组下标值]
2.稀疏数组,下标不是从0开始,长度length大于实际数组元素个数。 var arr = [undefined]; 这个是给位置0设置了undefined, 而 var arr = new Array(99) ,虽然给数组安排了99个位置,但是这99个位置占了但是里面没有内容。 简单的说就是如果那个位置有值的话用in判断就返回true,反之则返回false。
var arr = new Array(100); arr[98] = 123; 98 in arr; //true : 98上key值存在 97 in arr; //false :: 97上key值不存在
稀疏数组: 1. var arr1=[undefined];//有第0个元素,为undefined 2. var arr2=new Array(1);//稀疏数组,数组长度为1,但并没有定义arr[0] 3. var arr3=[,,];//稀疏数组,定义了两个个undefined数组元素,没有规定arr[0]就是undefined 所以,0 in arr1//return true(表示key 0 是否在arr1中); 0 in arr2//return false; arr1.length = 100; arr1[99]=123; 99 in arr1//return true; 98 in arr1//return false(因为arr[98]并没有被定义) 凡是没有显示定义数组索引的,都是稀疏数组
3)数组方法
join()--将数组转换为字符串,可打印数组。 join("")给数组添加组合符号。如arr=[a,b,c];arr.join("_");//"a_b_c",原数组未被修改 reverse()倒序排列数组。注意原数组会被修改 sort()按照字母的顺序排序,但是无法满足复杂的字符串,即无法按数字大小排序 sort(function(a,b){return a-b})---在sort方法中定义一个函数,如果是升序排列的话,前面的值要小于后面的值,就要返回一个负数;
如果是降序排列的话;前面的数会大于后面的数,返回一个正数。注意原数组会被修改。 concat()合并数组,不会修改原数组 slice(a,b)表示截取数组第a个索引元素到第b个索引元素结束,左闭右开;当a,b值为负数时,表示倒着截取数组,且不对原数组修改。 splice(a)只有一个参数时,表示在a索引的位置截断数组,形成两个数组; splice(a,b)有两个参数时,表示在a索引的位置截取b个元素形成新数组。 splice(a,b,新元素) splice方法原数组会被修改。
数组的方法(ES5的方法) 1.forEach 遍历 2.map 映射 var arr = [1,2,3]; arr.map(function(x){ return x +10; });//【11,12,13】 arr;//[1,2,3] 原数组未被修改 3.filter 数组过滤 arr = [1,2,3,4,5,6,7,8,9,10]; arr.filter(function(x,index){ return index%3 ===0 || x>=8; }); [1,4,7,8,9,10]; arr; 原数组未被修改 4. 数组判断 every 所有的元素都符合条件 返回true 否则返回false some 某个元素符合条件则返回true 若所有的元素都不符合条件则返回false var arr =[1,2,3]; arr.every(function(x){ return X<10; });//true arr.every(function(x){ return x < 3 });//false
6.reduce 数组中的元素两两之间的某些操作 从左到右 reduceRight 从右往左 var arr = [1,2,3]; var sum = arr.reduce(function(x,y){ return x+ y },0);//6 传入了一个0 则x相当于0 y 相当于1 然后值1 ;
然后此时 x 相当于1 y 相当于2 和为3 x相当于3 y 相当于3 和为6 所以结果为6 如果不传入0这个值 则X从数组的第一个元素开始 循环两两元素相加 reduceRight 同理 只不过是从右往左开始两两操作 7.indexOf 数组的检索 indexOf(a,b);a 是查找的元素 b是开始查找的位置 正数从左数的位置 负数从右数的位置 indexOf(元素); 返回的是元素的下标 不存在返回-1 lastIndexOf 从右往左查。
8.判断是否是数组,有 4 种方法:
1)Array.isArray(arr)
2)arr instanceof Array 3)Object.prototype.toString.apply(arr)
4)arr.constructor === Array
数组和对象的区别
相同点:1.都可以继承。 2.数组是对象,对象不一定是数组。 3.都可以当作对象添加删除属性。 不同点:1.数组会自动更新length。 2.索引访问数组比访问一般对象属性迅速。
字符串类似数组,可以通过索引访问字符串中的元素,但是没有数组中的一些操作方法,字符串可以通过如下的方式使用join()方法: 使用"_"来连接字符串:Array.prototype.join.call(str,"_");