Javascript细节

90 阅读4分钟
  1. 函数提升的作用是解决函数递归调用的问题,如果未提升,则相互调用无法实现
  2. 常量const定义的规则往往是大写的形式
  3. 浮点数使用64存储时,最多只能存储52的小数位,对于一些超过52位的小数位会直接截取,所以存在运算丢失精度的问题
  • 小数位截取往往出现丢失精度问题,但是整数不会出现丢失精度,所以小数位可以通过转换为整数进行运算
  1. 字符串逆序
str.split('').reverse()
  1. 栈先进后除原则
  2. 斐波那契数列
前两项和等于第三项
1 1 2 3 5 8 13 21 34 55 89
  1. charAt(int index)方法是一个能够用来检索特定索引下的字符

  2. sort排序字符串使用的是ACSii码进行判断

  3. 字符串统计字符出现的次数

1.字符串转换为字符
2.字符进行sort排序
3.字符lastIndexof和字符第一个出现的位置进行相减统计字符出现的个数
  1. hasOwnProperty() 判断自身的属性,继承的属性不属于自身的属性
  2. 字符串为空判断
str==='' || str.trim().length===0
  1. 类型判断
a instanceof Array
a instanceof object
type (function(){}) =>function
  1. reduce累加器
arr.reduce(callback,[initvalue  ])
  1. 函数声明,函数表达式
函数声明
function aa(){}
函数表达式
var aa=funtion(){}

形参改变不会影响实参,除非形参不是基本数据类型

实参没传,形参不能改变实参

arguments.callee等于函数名

  1. this指向
var value=10;
var obj={
  value:100,
  method:function(){
     var foo=function(){
        console.log(this.value)
     }
     foo();  =>无调用者,则为window
     return this.value;
  }
}
obj.method()   => 10  100

bind改变this指向时需要新建个函数赋值再执行 var a=b.bind(this);a() 而call,apply不需要赋值过程

var user={
 sport:'basletball',
 data:[
 {name:'cao teache',age:18}
  {name:'cao teache',age:30}
 ],
 clickHander:function(){
    //此处this指向user对象
    this.data.forEach(
    function(person){
      console.log(this);  //window
      console.log(person.name+'is palying'+this.sport)  //this.sport =>undefined
    }
    )
 }
}

function f(k){
this.m=k;
return this
}
var m=f(1);
var n=f(2);
console.log(m.m)  //undefined
console.log(n.m)  //2
  1. argument (1)拥有length属性,其他属性(如索引)为非负整数,(对象中的索引会被当做字符串来处理);

​ (2)不具有数组所具有的方法;

const arrLike = { 0: 'foo', 1: 'too', 2: 'baz', length: 3 }; const arr = Array.prototype.slice.call(arrLike); // 注:类数组转换为数组首先Array.prototype,slice.call(arguments)的结果是将arguments对象转换为一个Array对象,在后面可以直接调用数组所具有的方法; const newArr = Array.from(arrLike); const newArr2 = [].slice.call(); console.log(arr, newArr, newArr2); // ["foo", "too", "baz"], ["foo", "too", "baz"], ["foo", "too", "baz"] console.log(arrLike); // {0: "foo", 1: "too", 2: "baz"}

// 1. Array.prototype.slice():slice()方法 提取字符串中的某个部分,返回一个新字符串(被提取的部分); // 2. Array.slice ():返回一个新数组,包含从 start 到 end (不包含结束位置)的元素; // (1). slice()方法不会修改原数组,若想删除数组汇总的一段元素,使用Array.splice()方法; 1 2 3 4 5 6 7 8 9 10 11 1 2 3 4 5 6 7 8 9 10 11 Array.prototype.slice()方法

(1)Array.prototype.slice()方法表示数组原型中的slice方法,注意这个slice方法返回的是一个Array类型的对象;

// slice的内部实现 Array.prototype.slice = function (start,end) { let result = new Array(); start = start || 0; end = end || this.length; // this指向调用的对象,当用了call后,改变了this的指向,也就是指向传进来的对象,这是关键 for (let i = start; i < end; i++) { result.push(this[i]); } return result; } 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 (2)能调用call()的只有方法,所以不能使用[].call()这种形式,得用[].slice,而call的第一个参数表示真正调用slice的环境变为了arguments对象,所以就好像arguments具有了数组的方法;

(3)通用直接转为数组:Array.from()

类数组和数组的区别

instanceof constructor toString() isArray()

  1. 修改对象默认属性 使用Object.defineProperty定义对象属性,修改必须使用Object.defineProperty,无法person.name定义赋值 属性如果未设置,默认为false
Object.defineProperty(person,'name',{
 writable:false, //不可外部修改
 value:"13123",
 configurble:false, //不可删除
})
console.log(person.name)  //13123
person.name='444'
console.log(person.name) //13123

writable属性定义false,则下次没法再修改,只能销毁对象,重新创建定义

Object.defineProperty(person,'name',{
 value:"13123",
 configurble:false, //不可删除
})
//不可修改 writable默认为false
Object.defineProperty(person,'name',{
 value:"13123",
 configurble:true, //可删除
})
  • 对象访问器属性 get set
let book={
year_:2017,
edition:1,
}
Object.defineProperty(book,'year',{
 writable:false, //不可外部修改
 value:"13123",
 configurble:false, //不可删除
 get(){
 return  this.year_;
 },
 set(newValue){
  this.year_=newValue
  this.editon+=newValue-2017
 }
})
book.year=2018
console.log(book.editon)  //2
console.log(book.year_)  //2018

_结尾约定外部不能访问 实际也能访问 _开头约定外部访问

let book={
  yerr_:100,
}

对象点number的形式不能使用 a.1 不可

  1. 对象的创建方式
  • 普通定义
  • new Object() 前两种方式重复代码太高了
  • 基于工厂模式创建 使用工厂模式减少了代码的重复率,都是基于Object创建属性,无法将属性给予赋值的变量
function createPerson(name,age,address){
//内部通过Object()构造函数生产一个对象,并添加各种属性
var o=new Object();
o.name=name;
o.age=age;
o.getName=function(){
return this.name;
}
o.address=address
return o;
}
var person=createPerson('caoteacher',18,{
name:"上海",
code:'10000'
})
  • 基于构造函数 构造函数方式可以将属性赋予new实例化的对象上,即调用的this,但是存在问题
function Person(name,age,address){
this.name=name;
this.age=age;
this.address=address;
this.getName=function(){
return this.name;
}
}

var person=new Person('cao',18,{
name:'上海',
code:'10000'
})
var person1=new Person('cao',18,{
name:'上海',
code:'10000'
})

person.getName和person1.getName不一样,会存在浪费空间的问题,而且在执行前已经绑定到对应的this上了

  • 基于原型对象的模式
function Person(){
//通过prototype属性添加属性和函数
Person.prototype.name='cao teacher';
Person.prototype.age=18;
Person.prototype.address={
name:"上海",
code:'10000'
}
Person.prototype.getName=function(){
return this.name
}
}

var person=new Person()
var person2=new Person()'
console.log(person.getName===person2.getName)
console.log(person.name===person2.name)

不同的实例会共享属性和方法,解决上一个方法的问题,但是改变其中的属性,实例都会改变

  • 构造和原型混合模式 属性不共享,方法共享
function Person(name,age,address){
this.name=name;
this.age=age;
this.address=address;
}
Person.prototype.getName=function(){
return this.name
}

var person=new Person('cao',18,{
name:'上海',
code:'10000'
})
var person1=new Person('cao2',18,{
name:'上海',
code:'10000'
})

person.getName===person1.getName
person.getName()  //cao
person1.getName()  //cao2  

每次实例生成都会在原型链上加入一次getName

  • 动态原型模式 只在第一次实例生成在原型链上加入一次getName
  1. 深克隆,复杂数据类型相互独立,不会受影响;浅克隆相互会受影响
//浅克隆
var b=Object.assign({},a)
//深克隆
//针对对象和数组
JSON.parse(JSON.stringify())  //对于包含正则/函数/嵌套循环引用会存在问题

20.原型链(通过_proto_连接) new出来的实例_proto_对应prototype的方法 new出来的实例contructor对应构造函数

Person.prototype={
constructor:Person,  //重写原型对象这个属性必须加,如果未写则指向Object
name:'',
}

//如果在重写原型对象的前实例new,则new出来无法获取新添加的原型属性

原型的方法可以保持new出来的多个方法相同

  • 内置构造函数 js特殊的内置构造函数
String._proto_===Function.prototype
Number._proto_===Function.prototype
Array._proto_===Function.prototype
Object._proto_===Function.prototype
Date._proto_===Function.prototype
Function._proto_===Function.prototype

普通的函数都是指向Object.prototype 原型链查找如果未找到则为undefined

  1. 继承
  • 原型链继承缺点:

1.非基本数据类型(引用数据类型),其中一个实例化出来进行修改,则其他实例化会同步更改

2.无法实现多继承,会覆盖继承

3.在创建字类前,无法向父类传递参数

4.为字类创建属性或者函数,只能在实例之后(Car.prototype=new Animal()),否则会重写原型

Car.prototype.aa=funciton(){}  //应放在后面
Car.prototype=new Animal()
  • 构造继承,改变this的指向 并且可以实现多继承,
//实例只是子类的实例,并不是继承对象的实例
Animal.call(Cat)
var Car=new Cat('')
cat instanceof Cat    //true
cat instanceof Animal  //false
//只能继承自身的属性,但是无法调用原型链上的方法,
//服务复用父类(Animal)的实例函数
每次实例new都需要call,损耗性能
  • 复制继承
for in遍历
可以实现多继承
每次实例new都需要call,损耗性能
实例只是子类的实例,并不是继承对象的实例

  • 组合继承
缺点:多个new会出现重复定义问题
  • 寄生继承
//杜绝重复定义问题
function Cat(name){
Animal.call(this);
this.name=name;
}
//原型两次绑定加入函数去处理重复定义问题
(function(){
 var Super=function(){};
 Super.prototype=Animal.prototype;
 Cat.prototype=new Super(); //原型上有属性会直接使用原型实例,否则使用父类的原型
 Cat.prototype.constructor=Cat;
})
  1. new实例化 功能:1.实现return 2.改变this指向 3.添加属性

  2. HTMLCollection和NodeList

var ad2=document.getElementById("ad").childNodes;
ad2.item(1)  //第一个节点

var main=document.getElementById("ad").children;
main.namedItem('usename')  //namedItem有限找到id,然后是class

24.捕获和冒泡

element.addEventListener(event, function, useCapture);

useCapture false是冒泡,true是捕获

event.stopPropagation() 阻止冒泡

25.阻止默认行为

event.preventDefault() 26. ajax onload事件

27.反序列化

1.JOSN.parse(str,function(key,value){})
2.eval("("+json+")")    //需要加入括号  

28.跨域解决缺点:不能请求post

Queryselector 选择第一个

queryselectorAll 选择所有元素

移入:onmouseenter 不支持冒泡

Onmoursover 支持冒泡

移出 onmouseleave 不支持冒泡

onmouseupout 支持冒泡

document activeElement焦点元素

childNodes返回所有子元素

paretInt 返回首个数字

tofixed()会进行四舍五入

toPricison()保留小数点前后的总位数

lastindexof括号可以传两个值,一个的时候取最后元素匹配的位置,没匹配到为-1,第二个存在参数则为截取元素从0到该为止,然后再匹配

split第二个元素为分割出数组的元素个数

filter返回筛选符合条件的

every 每个元素都符合条件才为true 否则为false

some 有一个元素符合条件则为true 否则为false

ts 1.强类型不允许隐形类型改变

2.动态类型 可能类型会随时变化

javascript 弱类型 动态类型

flow 类型注解工具,100:number

flow any mixed类似,any是弱类型,mixed是强类型

enum枚举对象

类型断言 as

动态属性[]

protected只允许在子类访问的成员 public private 不允许继承和使用,只允许自身内部使用,子类想使用可以在父类自身实例化,爆出方法给子类使用

implement abstract抽象类/方法标识,不是实例化该类,只能继承 泛型,定义时不定义类型,使用的时候才定义类型,把不明确的类型用T表示

declare类型申明

  • 将十进制转换为二进制或十六进制
const num = 10;
num.toString(2); // 输出: "1010"
num.toString(16); // 输出: "a" 
num.toString(8); // 输出: "12"
  • 声明和初始化数组
const array = Array(5).fill(''); 
// 输出
(5) ["", "", "", "", ""]

const matrix = Array(5).fill(0).map(()=>Array(5).fill(0)); 
// 输出
(5) [Array(5), Array(5), Array(5), Array(5), Array(5)]
0: (5) [0, 0, 0, 0, 0]
1: (5) [0, 0, 0, 0, 0]
2: (5) [0, 0, 0, 0, 0]
3: (5) [0, 0, 0, 0, 0]
4: (5) [0, 0, 0, 0, 0]
length: 5

  • 对字符串、数字或对象数组进行排序
//字符串排序
const stringArr = ["Joe", "Kapil", "Steve", "Musk"]
stringArr.sort();
// 输出
(4) ["Joe", "Kapil", "Musk", "Steve"]

stringArr.reverse();
// 输出
(4) ["Steve", "Musk", "Kapil", "Joe"]


//数字排序
const array  = [40, 100, 1, 5, 25, 10];
array.sort((a,b) => a-b);
// 输出
(6) [1, 5, 10, 25, 40, 100]

array.sort((a,b) => b-a);
// 输出
(6) [100, 40, 25, 10, 5, 1]


//对象数组排序
const objectArr = [ 
    { first_name: 'Lazslo', last_name: 'Jamf'     },
    { first_name: 'Pig',    last_name: 'Bodine'   },
    { first_name: 'Pirate', last_name: 'Prentice' }
];
objectArr.sort((a, b) => a.last_name.localeCompare(b.last_name));
// 输出
(3) [{…}, {…}, {…}]
0: {first_name: "Pig", last_name: "Bodine"}
1: {first_name: "Lazslo", last_name: "Jamf"}
2: {first_name: "Pirate", last_name: "Prentice"}
length: 3