一、判断变量类型

基本数据类型: 1,null, 2 ,undefine 3, number,4,string,5,bool

6,symbol(独一无二的值) 由于每一个Symbol值都是不相等的,这意味着Symbol值可以用于对象的属性名,保证不会出现同名的属性

7,bigint 大数据

1、type of,

基本数据类型, type of可以判断,但是引用类型除了函数外,它的判断都是"object"。

2、instance of

instanceof运算符用来判断一个构造函数的prototype属性所指向的对象是否存在另外一个要检测对象的原型链上

所以,只能用来判断两个对象是否属于实例关系, 而不能判断一个对象实例具体属于哪种类型。

弊端:number,string,boolean这三种类型,只有通过构造函数定义才能检测出,

直接定义检测不出




外部js文件中如何引用jquery_引用外部js


3、constructor,

是原型prototype的一个属性,当函数被定义时候,js引擎会为函数添加原型prototype,并且这个prototype中constructor属性指向函数引用, 因此重写prototype会丢失原来的constructor。

construte 和 instanceof的区别和作用

constructor属性来判断一个实例对象是由哪个构造函数构造出来的,constructor所指向的的构造函数是可以被修改的

instanceof 运算符通俗来将就是判断两个对象是否属于实例关系,

4、使用Object.prototype.toString.call

二、作用域,作用域链 变量提升

JavaScript变量的作用域, 全局变量和局部变量

函数内部可以直接读取全局变量。另一方面,在函数外部自然无法读取函数内的局部变量。但是通过闭包,可以在函数外面访问到内部的变量!

作用域链

自由变量:函数中没有定义的变量

自由变量往父级作用域找,一层层往找,直至找到全局变量。

说下对变量提升的理解

1、所有申明都会被提升到作用域的最顶上;

2、同一个变量申明只进行一次,并且因此其他申明都会被忽略;

3、函数声明的优先级优于变量申明,且函数声明会连带定义一起被提升

三、闭包

函数内部可以直接读取全局变量。另一方面,在函数外部自然无法读取函数内的局部变量。但是通过闭包,可以在函数外面访问到内部的变量!

闭包就是将函数内部和函数外部连接起来的一座桥梁。

它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。

1:由于闭包会使得函数中的变量都被保存在内存中

2:闭包会在父函数外部,改变父函数内部变量的值

闭包使用场景

1、函数作为返回值

2:函数作为参数传递

四、this

this:js中的执行环境主要有两种:全局执行环境和函数执行环境

普通函数跟箭头函数中this的指向问题

箭头函数和普通函数的区别如下。

普通函数:根据调用我的人(谁调用我,我的this就指向谁)

this总是代表它的直接调用者(js的this是执行上下文), 例如 obj.func ,那么func中的this就是ob

使用call,apply,bind(ES5新增)可以改变this指向

箭头函数:根据所在的环境(我再哪个环境中,this就指向谁)


外部js文件中如何引用jquery_数组_02


外部js文件中如何引用jquery_原型链_03


this应用场景

1:作为构造函数执行


function Foo(name){
this.name=name
}
var f=new Foo('lily)


2:对象属性执行


var obj={
name;'A';
printF:function(){
console.log(this.name)
}
}
obj.printF


3:普通函数执行


function fn {
console.log(this)//this===window
}
fn()


4:call apply bind执行,改变this的值


function f(name,age) {
 console.log(name)
 console.log(this)
}
f.call({x:100},'lily',23) //this是{x:100},


五、原型链

原型规则

1:所有引用类型(数组,对象,函数)都有对象的特性.null除外


var obj={}
obj.a=100
var arr=[]
arr.a=100
function Foo(name,age) {
 this.name=name;
 this.age=age
 console.log(this)
}


2:所有引用类型都有一个隐式属性:__proto__,属性值是一个普通对象

3:所有函数都有一个prototype显式原型属性,属性值也是一个普通对象

4:所有的引用类型的隐式属性__proto__指向的它构造函数的显式原型属性prototype属性

arr.__proto__===Array.prototype

5:当试图去得到一个对象的属性时,如果这个对象本身没有这个属性,会去它的_proto_去寻找(也就是它的构造函数prototype寻找),而这个它的_proto_又是一个对象,也有__proto__属性,就这样一直往上找,这就是原型链,直到找到Object的原型的时候就到了头,而Object.prototype=null,


外部js文件中如何引用jquery_外部js文件中如何引用jquery_04


六、创建对象有几种方法

//字面量


var o1=new Object({name:'01'})        //new Object一个对象
var o2={name:'o1'}
//构造函数
var M=function(name){
this.name=name
}
var 03=M('03')


//Object.create


var p={name:'p'}
var o4=Object.create(p)


//工厂模式,返回一个对象


function person(name,age) {
 var obj = new Object();
        obj.name = name;
        obj.age  = age;
        obj.play = function () {
            console.log('玩游戏')
        }
 return obj
    }
       var per3 = person('王五','20')


//构造函数


function animal(name, age) {
 this.name = name;
 this.age = age;
 this.food = function () {
            console.log('骨头')
        }
    }
 var ani1 = new animal('泰迪',3) // ani1称为实例化对象


七、new运算符原理


var M=function (name) {
    this.name=name
}
var new2=function (func) {
    var o=Object.create(func.prototype) .        //1:生产一个空对象,空对象继承构造函数的原型对象
    var k=func.call(o)                   //2:执行构造函数
    if (typeof k==='object'){ 。   //3:判断构造函数执行结果是不是对象类型
        return k;
    } else {
        return o
    }
}


八、继承的方法

1)原型链实现继承的思想:利用原型让一个引用类型继承另一个引用类型的属性和方法。


function SuperType(){
      this.property=true;
}
SuperType.prototype.getSuperValue=function(){
      return this.property;
}
function SubType(){
      this.subproperty=false;
}
//通过创建SuperType的实例继承了SuperType
SubType.prototype=new SuperType();


SubType.prototype.getSubValue=function(){
      return this.subproperty;
}
var instance=new SubType();
alert(instance.getSuperValue());  //true


缺点:当一个实例修改会改变另一个实例,原型链上的原型对象是公用的

2)借用构造函数实现继承:子类型构造函数的内部调用父类型型构造函数,通过使用apply()和call()方法可以在新创建的对象上执行构造函数。


function SuperType(){
 this.colors=["red", "blue", "green"];
}
function SubType(){
 //继承SuperType
   SuperType.call(this);
}
var instance1=new SubType();
instance1.colors.push("black");
alert(instance1.colors);  //red,bllue,green,black
var instance2=new SubType();
alert(instance2.colors);  //red,blue,green


缺点:方法都在构造函数中定义,因此无法复用函数。在父类的原型中定义的方法,对子类型而言是不可见的。

3)组合继承 原型链实现对原型方法的继承,而通过借用构造函数来实现对实例属性的继承。这样,既通过在原型上定义方法实现了函数的复用,又能够保证每个实例都有它自己的属性。


function SuperType(name){
 this.name=name;
 this.colors=["red", "blue", "green"];
}
SuperType.prototype.sayName=function(){
      alert(this.name);
};
function SubType(name, age){
 //继承属性    使用借用构造函数实现对实例属性的继承
      SuperType.call(this,name);
 this.age=age;
}
//继承方法     使用原型链实现
SubType.prototype=new SuperType();
SubType.prototype.constructor=SubType;
subType.prototype.sayAge=function(){
      alert(this.age);
};
var instance1=new SubType("mary", 22);
instance1.colors.push("black");
alert(instance1.colors);   //red,blue,green,black
instance1.sayName();  //mary
instance1.sayAge();  //22

var instance2=new SubType("greg", 25);
alert(instance2.colors);   //red,blue,green
instance2.sayName();  //greg
instance2.sayAge();  //25


4)ES6 引入class,可以通过extend实现继承。

九、类数组

输出是个对象,但他的原型并不指向Array。

它的特性是:

  • 1)具有length属性;
  • 2)按索引方式存储数据;
  • 3)没有内置方法,不具有数组的push()、pop()等方法

//类数组示例

var a = {'1':'gg','2':'love','4':'meimei',length:5};

Array.prototype.join.call(a,'+');//'+gg+love++meimei'

//非类数组示例

var c = {'1':2}; //没有length属性就不是类数组

javascript中常见的类数组有 arguments对象和 DOM方法的返回结果。比如 document.getElementsByTagName()。

转为数组

1:Array.prototype.slice.call(a)

2:Array.from(li)

九、高阶函数

接收函数作为参数或者返回函数的函数,都可成为高阶函数。所以常见的方法有:map,filter,bind,apply等。

需要了解一下,高阶函数实现AOP。

十、柯里化函数

柯里化,实现上,就是返回一个高阶函数,通过闭包把传入的参数保存起来。

当传入的参数数量不足时,递归调用 bind 方法;数量足够时则立即执行函数。

十一、for 循环效率

for > forEach > map

如何选择对应的循环呢:

  • 如果需要将数组按照某种规则映射为另一个数组 map
  • 如果需要进行简单的遍历 forEach 或者 for of
  • 如果需要对迭代器进行遍历 for of
  • 如果需要过滤出符合条件的项 filter