七--js基础

基本类型String,Boolean,Number,undefined,null
引用类型:object:Array,Function,Date
undefined == null;NaN!=NaN;对象得赋值变量去比较,因为它是引用,重新定义一个值一模一样的对象,它们存储的地址是不一样的。
typeOf null==Object=>true
1、js 数组
a=[1,2,3];
delete a[0];a变成了[undefined,2,3];长度不变。
对比a[0]=undefined,这两个操作结果都一样,但是对 in操作就不一样,如:
delete-----if(0 in a)=>false
直接赋值undefined ----if(0 in a)=>true
对于in操作符,new Array 生成的空数组用in操作符都是返回false
直接将a的长度减一也能删除最后一个数据。
总结 未明确赋值的数组 用in操作符都返回false。
数组方法:
Array.prototype.join:将数组转为字符串

var arr=[1,2,3];
arr.join('_');//‘1_2_3’
//设置重复字符
function repeatString(str,n){
	return new Array(n+1).join(str);
	//空的数组join undefined会被忽略掉
}
repeatString('a',3);//'aaa'

Array.prototype.join:将数组逆序
Array.prototype.sort:将数组排序

var arr=['a','c','b'];
arr.sort();//['a','b','c']
arr=[13,24,51,3];
arr.sort();//[13,24,3,51],将数组转为字符串进行排序,且原数组也会改变
arr.sort(fuction(a,b){return a-b})//[3,13,24,51]
//返回正数则会交换,所以a-b是升序,b-a是降序
//相等返回0

Array.prototype.concat:将数组合并,原数组未修改

var arr=[1,2,3];
arr.concat([10,11],13);//[1,2,3,10,11,13]
arr.concat([1,[2,3]]);//[1,2,3,1,[2,3]],只会拉平一次

Array.prototype.slice:返回一部分数组,原数组不修改

var arr=[1,2,3,4,5];
arr.slice(1,-1);//[2,3,4],不包括endindex

Array.prototype.splice:将数组拼接,原数组改变

arr.splice(index,len,item);//索引,个数,插入数据

Array.prototype.forEach(fuction(el,index,a){}):数组遍历,第一个参数为数组遍历的当前项的值,第二个为数组下标,第三个为数组本身
Array.prototype.map:数组映射,需要return一个返回值
对于forEach和map都不改变数组本身,但对于对象引用来说如果修改其内部属性是会改变的
Array.prototype.filter:数组过滤,原数组不改变

var arr=[1,2,3];
arr.filter((x,index)=>{if(x>1){return true}})
//返回true才会留下该项

Array.prototype.every和some,includes:数组判断,原数组不改变

var arr=[1,2,3];
arr.some(()=>{return x==5})//false
arr.some(()=>{return x==2})//返回true,只要有一个元素符合就返回true
arr.every(()=>{return x < 3})//false
arr.every(()=>{return x < 5})//返回true,全部符合才会返回true,有一个不符合就返回false
arr.includes(5);//false,匹配不到为false

Array.prototype.reduce和reduceRight:数组从左至右遍历和从右至左遍历,传入的值是上一次遍历的结果,原数组不改变

var arr=[1,2,3]
var sum = arr.reduce((x,y)=>{return x+y},0);//结果是6
//这里就是做了一个累加的操作,每次计算的结果作为下一次输入x的值,y为当前项的值,初始赋值0传入给x。若不赋值,则默认x,y取数组第1,2项值
//求最大值
var max = arr.reduce((x,y)=>{return x>y?x:y})
//reduceRight就是x,y是从右到左开始赋值的

Array.prototype.indexOf和lastIndexOf:数组检查

var arr=[1,2,3,2,1]
arr.indexOf(1);//0,返回值所在的下标,找不到返回-1
arr.indexOf(1,1);第二个值为从第几个下标开始查找,返回-1
arr.lastIndexOf(2);//3,从右往左查,先找到先返回
arr.lastIndexOf(2,-3);//1,匹配到左边第一个2


Array.prototype.find和findIndex:数组查找,前者符合条件返回数组项,后者返回符合项的下标
Array.isArray:判断是否是数组,是构造器的方法,不能对象.Array去使用,必须Array.isArray([])这样来使用,返回为true,
[] instanceof Array 为true
[].constructor ===Array 为true
最后对比数组和对象,数组是对象,对象不一定是数组,都可以当作对象添加删除属性;数组自动更新length,按下标访问更快速,Array.prototype继承Object.prototype
字符串和数组

var str = '123';
str.charAt(0);//1
str[0];//1
Array.prototype.join.call(str,'_');//'1_2_3'
//字符串是以一种不可改变的数组,它没有数组的一些方法,可以用join.call()来实现

2、属性检测

var descriptor = Object.getOwnPropertyDescriptor(Obj,'prototype');
//descriptor.configurable 为false,则表示该属性无法被配置,删除属于配置的一种即delete obj.prototype 返回false

定义的全部变量或局部变量还有函数都不能被删除。隐士创建的全局变量即 a=1;这是隐式创建了全部变量,但是它可以被删除,eval()内定义的变量也可以被删除,这个函数是创建了一个独立作用域。
hasOwnproperty():检测对象自己的属性是否存在
propertyIsEnumerable():检测属性是否是可枚举的,即是否可遍历
toString为Object.prototype上的属性,obj.propertyIsEnumerable(‘toString’)返回false,因为原型链上的大多数属性都是不可枚举的,所以console.log(obj)打印出来的都是对象自己的属性,object.keys()这个方法也是只能读取可枚举属性名称;toString in obj为true,但是for(key in obj ){}toString是轮询不出来的。
Object.defineProperty(obj,‘price’,{enumerable:false,value:100});这是对对象添加属性的方法,默认的标签属性都为false
new 或字面量添加的属性的标签默认为true

function foo(){}
Object.defineProperty(foo.prototype,'z',{get:function(){return 1}})
var obj = new foo();
console.log(obj.z)//1
obj.z = 10;
console.log(obj.z)//仍然1

注:分割线上下不可以共存
不可以同时指定getter、setter访问器和值(value)或可写属性(writable)

       Object.defineProperty(person, 'age', {
            value: 18,
            writable: true, //控制属性是否可以被修改,默认值是false

///-------------------------------------------
            get() {
            },
            set(value) {
            }
        })

当尝试赋值z属性时,对象上没有这个属性,会去原型链上查找发现有该属性的get/set方法时,这时会优先走get/set方法,就不会添加对象自己的属性z并赋值的操作。若writable设置为True,不可以有get/set方法,那么z属性可被添加赋值,且z属性是obj的自身属性。

Object.getOwnPropertyDescriptor({pro:true},'pro');
//object{value:true,writable:true,enumerable:true,configurable:true}

以上属性都是属于数据属性,分别为值,是否可写赋值,是否可枚举、可被遍历,是否通过delete删除属性从而重新定义属性、是否可修改属性的特性、或能否把属性修改为访问器属性,默认为true。一般configurable为false时,其他属性标签都不可以被修改,但当writeable为true时,可以将writeable改成false。
//一次定义多个属性
object.defineProperties(person,{title:{value:‘fe’,enumerable:true},
corp:{value:‘ba’,enumerable:true}})
对象属性除数据属性外还有访问器属性
configurable:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或能否把属性修改为访问器属性,默认为false
enumerable:表示能否通过for-in循环返回属性,默认为false
Get:在读取属性时调用的函数,默认值为undefined
Set:在写入属性时调用的函数,默认值为undefined
前面说过了访问器属性getter、setter和数据属性值(value)或可写属性(writable)不可共存。即只能定义一种类型的属性。

extensible标签表示对象上的属性是否可扩展

var obj = {x:1,y:2}
object.isExtensible(obj)//true,是可扩展的;
Object.preventExtensible(obj);//将其变为不可扩展
obj.z = 1;
console.log(obj.z)//为undefined,因为无法添加
Object.seal(obj);//将对象上的configurable设为false
Object.isSealed(obj);//true,判断对象是否是不可配置的,不可删除
Object.freeze(obj);//将都对象冻结,不可写,不可改,不可添加,不可删除,不可更改配置
Object.isFrozon(obj);//true.判断对象是否被冻结

以上方法操作都不影响原型链上的属性。
3、序列化
obj={val:undefined,a:NaN,b:Infinity,c:new Date()}
JSON.stringify(obj)=>“{“a”:null,“b”:null,“c”:“2015:01-20T14:15:45910z”}”
说明值为undefined的key序列化后不存在,时间转为UTC时间
序列化-自定义

var obj={x:1,y:2,o:{01:1,02:2,toJSON:function(){return this.01+this.02}}}
JSON.stringify(obj);//"{"x":1,"y":1,"o":3}",序列化时执行toJSON方法
var obj={x:1,y:2};
obj.toString();//"[Object Object]"
obj.toString = function(){return this.x +this.y};//添加一个自定义的toString的方法
+obj;//3 转换数字会调用toString()方法
"resulit"+obj;//"result 3"加号运算符也会调用toString()方法
obj.valueOf = function(){return this.x + this.y + =100}
+obj;//103;尝试把对象转换为基本类型会调用valueOf()
"result" +obj//"result 103",依旧时调用valueof

当valueof和toString同时存在时,不管一元加号还是字符串拼接的加号,都会先对象转为基本类型,所以会先找valueOf(),若valueof返回基本类型,结果就时valueof的值,若返回对象或没有,就找toString(),若toString返回对象或没有,则报错。
4、apply,call,bind
apply的参数是数组,call参数是一个一个的,bind需要先声明,在执行,他们都是为了改变this指向的。bind比apply,call更高效,优先。
若传入的不是对象是基本类型,在浏览器下会转为相应的对象,比如apply(7,[]);则会转为number(7)对象

function f(){return this.a}
var g = f.bind({a:'test'})//将f的this指向{a:'test'}
console.log(g())//a 为test
var o = {a:37,f:f,g:g}
console.log(o.f(),o.g())
//f:37,g:test,说明bind优先

bind使用

function add(a,b,c){
	return a+b+c;
}
var func = add.bind(undefined,100);//不改变this指向,100赋给了a
 func(1,2);//返回100+1+2
var func2 = func.bind(undefined,200);//再次绑定,200赋值给b
func2(10);//100+200+10

function getConfig(color,size,otherOptions){
console.log(color,size,otherOptions)
}
var defaultConfig = getConfig.bind(null,'#cc000','1024*768');
defaultConfig(123);//打印'#cc000','1024*768',123
defaultConfig(456);//打印'#cc000','1024*768',456
//当有一部分配置不需要改变,一部分需要可以这样处理

bind 与new

function foo(){
this.b = 100;
return this.a;
}
foo();//this指向全局,windows,创建了一个全局变量b
var func = foo.bind({a:1});
func();//返回1,this指向{a:1}对象,且该对象还添加了b属性为100
new func();//{b:100}

在上述示例中,如果函数return返回对象则不管是new还是bind都是会返回这个对象,this并不指向这个对象,newd的this则指向空对象,bind的this则指向bind的对象。new若不返回或返回非对象,则返回this,this是一个空对象,原型对象__proto__指向foo.prototype。
最后一行代码生成的对象为{b:100},因为new情况下,bind无效,所以返回的this是一个只有b属性的对象

5、arguments
arguments是函数内接收实参的一个对象,是类数组,原型不是Array.prototype,没有slice,join等方法。
在非严格模式下,如function foo(x,y,zz);foo(1,2); arguments.length为2,arguments[0]即为x的值,重新给它赋值,x也会跟着改变,但修改第三个值即arguments[2]不会影响z,因为z未传参。foo.name为函数名,foo.length为形参长度;在严格模式下改变arguments不会影响x,y,z,但如果是对象还是会改变。
6、函数作用域
变量对象初始化的填充规则
1、函数参数(若为传入,初始化该参数值为undefined)
2、函数声明(若发生命名冲突,函数会覆盖其他)
3、变量声明(初始化变量值为undefined,若发生命名冲突,会被忽略)
例:

function foo(x,y,z){
function x(){};
console.log(x);//这里打印为function x(){}对应上述规则2
}
foo(100);
function foo(x,y,z){
function func(){};
var func;
console.log(func);//打印为func(){},对应规则3
}
foo(100);
function foo(x,y,z){
function func(){};
var func=1;
console.log(func);//打印为1,因为func变量赋值了,赋值是初始化后的执行阶段,所以func被变量的值覆盖了
}
foo(100);

测试:

console.log(x);//打印为function x(){} 因为后面有x()方法的声明,它前置了,变量x前置是undefined符合规则2覆盖
var x = 10;
console.log(x);//打印为10,执行时赋值为10
x= 20;
function x(){};
console.log(x);//打印为20,执行阶段被20赋值
if(true){
var a = 1;
}else{
var b = true;
}
console.log(a);//打印为1,因为a执行赋值1
console.log(b);//打印为undefined因为b声明了初始化为undefined,并没有执行

并不是所有对象都有Object.prototype所以它没有toString等方法比如
var obj = Object.create(null);
function abc(){}
abc.prototype=》abc{}
var binded = abc.bind(null)
typeof binded=>function
binded.prototype=>undefined

Object.create(null);----->obj._proto_为undefine
({})._proto_为Object.prototype
7、修改prototype
添加修改原型链上的属性会影响已创建或未创建的实例,给原型对象重新赋值新的对象,不会影响已经创建的实例的原型链,因为已创建的实例依旧指向原来的地址,新的实例才会指向新的原型对象指向的地址
继承:假设没有create的方法,可以模拟

if(!Object.create){
	Object.create = function(proto){
		function F(){}
		F.prototype = proto;
		return new F();
	}
}

8、eval和Function
eval可以将一段字符串以js代码的形式执行并返回结果。但是不能捕获错误。所以可以使用Function更方便。

module.exports = function evaluate (exp, data) {
  /* eslint-disable no-new-func */
  const fn = new Function('data', 'with (data) { return ' + exp + '}')
  try {
    return fn(data)
  } catch (e) {
    console.error('Error when evaluating filter condition: ' + exp)
  }
}

以上使用到了with,with 语句的原本用意是为逐级的对象访问提供命名空间式的速写方式. 也就是在指定的代码区域, 直接通过节点名称调用对象。with 通常被当做重复引用同一个对象中的多个属性的快捷方式,可以不需要重复引用对象本身。
比如:

var obj = {
    a: 1,
    b: 2,
    c: 3
};

要修改obj里的属性a/b等可以用如下with简写。注with不被推荐,因为可能导致性能泄漏和运行过慢。

with (obj) {
    a = 3;
    b = 4;
    c = 5;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值