ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
作用域 js中我们代码运行的环境叫做--作用域 作用域:全局作用域(可以加window.)--window; 私有作用域--函数执行时产生的作用域; 在全局作用域先定义的变量或者(系统自带的一些方法),相当于给全局window增加了一些属性名,我们可以直接写或者window.a都没有问题,不写默认window. ; console.log(a);--a is not defined;--预解释的时候没有找到a; a=12; 预解释:js代码执行之前,带var和function关键字的提前声明declare(定义),然后找完了,从上往下执行; 预解释只发生在当前作用域 var的预解释: ----代码执行之前先声明(只声明并没有赋值--定义undefined) ----从上往下执行代码 ----声明的变量和值进行关联 function的预解释: ----代码执行前先声明declare,但是和var不同的是,funciton连定义也完成了; ----函数作用域中,没有声明只是赋值的话,改变的是全局作用域下的变量; 在函数作用域下,也要进行预解释,如果函数内部有var和funciton的声明变量,形成函数的私有作用域,如果找不到,就往上一级的作用域里找,一直到window下的作用域,如果还找不到,就会报一个未定义的错误; 1预解释发现相重的,不重复声明;(只声明不代表不定义-- 遇到函数fn=3;function fn(){};(就是所谓的函数的优先级高)执行 的是函数的)函数不仅声明还定义了;; 2预解释是不管条件的; 3预解释只解释等号左边的,不预解释右边的;var fn=function a(){}; 4function中return后面的返回值(包括函数),不进行预解释; 5预解释只发生在一个脚本块中; 6函数中的形参相当于私有作用域下声明了一个变量,进行了预解释; 7闭包格式的函数--不进行预解释的 预解释:找var和function var a=12; function a(){ var a=13;console.log(a); } a=a(); console.log(a); 声明了a,遇到function发现已经声明了,function还有定义, 预解释声明--var a;a=function(){}; 执行:a=12;a=12(){}--number is not function 作用域: 函数没有执行的时候没有任何的意义 开辟一个新的内存,里面存储的是我们看上去像代码的字符串,然后函数里面存储的是对新的内存地址的访问 函数执行的时候,会形成一个私有的作用域(和我们开始的window类似),首先也是预解释,接下来从上往下执行代码 --正常情况下,我们一个function的生命周期: 出生:从预解释开始声明加定义-开辟一个新的内存块,让函数名存贮对这个内存块的引用地址 成长:函数执行,形成一个私有作用域,然后里面开始类似与window的新一轮预解释,代码从上到下执行; 死亡:一般情况下,私有作用域下的代码完成后,整个私有作用域就销毁了; 函数执行形成一个私有作用域,保护里面的变量不受外界的干扰(外面拿不到也修改不了)--这种机制叫做闭包; --一个function运行的时候,会形成一个私有的作用域,如果这个没有返回一个function(外面没有其他的东西占用他的内存的话),这个私有作用域执行完会自动销毁了,但是如果返回了一个funciton,而且之后函数外面还用到了这个function的话,那么这个函数是销毁不了的;--(一个函数是从形参开始执行的) this: [1]this和在哪定义和在哪执行没有半毛钱关系,和(函数执行时候的主体--主体是谁就是谁<主体就是.前面的>)有关系,没有的话默认的是window,而且this只出现在function中&或者全局作用域下; [2]绑定事件:谁绑定的主体就是谁 [3]闭包:主体是window 改变this关键字的方法 <1>call和apply 函数体.call(主体,形参,值,值)--一个一个 函数体.apply(主体,[形参,值,值])--数组的形式 call方法的第一个参数,是指函数运行是this的指向 从第二个参数开始,这些参数一次传给函数,传给函数的参数是以散列的方式存在的 apply方法最多只有两个参数,第一个参数和call相同,第二个参数是一个集合(数组),把整个集合传给函数方法,第二个参数相当于函数的arguments; call的特殊用法: fn.call(null)--如果一个方法和函数不能确定主体是谁,或者this指向了一个不存在的对象(null或undefined)则this指的是window; apply的特殊用法:--找出数组中最大值和最小值 Math.min(12,3,34,5,3,7,8,4,23,15)--Math.min的参数是一个个传进去的(散列式的),不能是数组; Matn.min(a)--错误的,不能是一个变量; Math.min.apply(null,a);--用apply传递的第二个参数是一个集合特点,把a这个集合,以整体的方式传给了min; <2>传递this 主体下声明var that=this 函数中的 this-->that(执行的时候没有声明向上级找--找到的是主体中的this) 用instanceof 不能够严格的判断一个实例是不是这个类的实例 function isArray(obj){ return Object.prototype.toString.call(obj)=="[object Array]"; } 面向对象: 实例创建对象: (1)单例模式--需要手动一个个创建;(避免使用全局变量或者全局的方法导致冲突,我们把需要的方法和变量当作对象数据类型的属性名和属性值存起来,每次执行的时候,对象.属性名就可以了,解决全局下的冲突问题);-----命名空间:我们把创建的那个对象名称之为命名空间; 第二种情况:var obj=(function(){ var a=""; function check(){ }; function submit(){ }; return {check:check,submit:submit}; })(); obj.check(); obj.submit(); (2)工厂模式--为了解决单例模式一个个生产的问题,实现批量生产 构造一个函数,函数里var一个obj对象,把方法和变量当作对象数据类型的属性名和属性值存起来,然后把obj返回; (3)构造函数--实例识别(差异) 对象、类、实例 js对象是一种复合类型,通过变量名存储和访问,对象是一个无序的属性集合 类是对象的细分,只需要new操作符就可以实现一个实例; 工厂模式和构造函数的区别: 不需要手动创建obj对象了,而且也不用return obj对象了; 原先obj统一替换成this(this是谁) [4]跟创建的实例有关系,创建的实例是谁,this就是谁 执行:定义变量=new 函数名(参数值) 我们把执行函数的时候,用new创建的方式称之为构造函数模式(实例创建方式),通过这种方式,我们把原先的那个函数称之为类,把返回的结果(就是var的那个变量)称之为这个类的一个实例 构造函数new执行过程:返回的实例也是一个对象数据类型; 也就是说,new一个函数的时候,首先会默认创建一个对象,也就是我们创建的实例(变量); 接下来会以实例(this)作为上下文,把对应的属性存起来; 返回的时候,实例就拥有了这些属性名和属性值; 默认的把我们创建的对象给我们的实例(变量名)--也就是我们创建的实例就是我们要的对象,换句话说this就是我们创建的这个实例 检测实例:instanceof--用来检测某一个实例是否是属于某个类的,属于返回true,不属于返回false;Js内置类:String,Object,Array,Number,Math,Date,RegExp Js中所有的对象数据类型都是内置Object类的一个实例 (4)基于构造函数的原型链模式:--解决产品差异化的同时,有相同的部分还可以共享----------构造函数不足:很多通用的方法没有实现共享,函数里边的相同方法一样才对,但是现有的构造函数模式,实现不了; 将需要共享的属性写在原型链prototype上,这样prototype上所定义的属性和方法就可以被一个类的实例共享了; prototype原理:每一个function都有一个天生自带的属性prototype,如果不是构造函数(new 函数)的话,这个函数没有任何意义; prototype存储的是一个对象数据类型,有自己的内存块,并且这个内存块上又有两个自带的属性constructor,__proto__;constructor是prototype这个对象数据类型特有的,而_proto_是所有对象数据类型都有的; 当我们new一个函数的时候,函数变成了类,并且返回一个实例,这个实例是对象数据类型的,所以有__proto__这个自带的属性,并且这个属性指向的是我们函数里面prototype自己的那个内存地址----所以我们变量(new)除了拥有函数里面自带的私有属性的时候,拥有了原型链__proto__属性; 一个对象被创建时,它的 __proto__ 属性和内部属性[[Prototype]]指向了相同的对象 (也就是它的构造函数的prototype属性).改变__proto__ 属性的值同时也会改变内部属性[[Prototype]]的值; 我们在调用实例上的属性名的时候,遵循这样顺序:先找私有的,私有的没有,在通过__proto__所在的类的原型上,如果在私有的中找到了,就不再往下找了; hasOwnProperty--检测某个实例上是否存在某个属性(是私有属性才有效,原型链上的无法检测) isPrototypeOf--检测原型链的对象是否存在于指定的对象实例中 Fn.prototype.isPrototypeOf(实例)------true Fn.isPrototypeOf--------------------------false hasOwnProperty()与for in的区别 1 in 判断某个对象中有没有某个属性--不管私有还是共有的; (属性名 in 实例) 2 hasOwnProperty()只能检测自定义属性,无法检测原型链属性。 我们常用的一些内置的类 如:String Array 等提供的方法都是在原型上的 "str".hasOwnProperty("split");//false String.prototype.hasOwnProperty("split");//true 只检测公有的属性--return !obj.hasOwnPorperty(key)&&(key in obj); js中我们常用的this的几种情况: 【】给元素绑定事件oDiv.onclick=function(){};this就是oDiv; 【】闭包(function(){this是window})(); 【】函数执行前的主体 fn()-->window obj.fn()-->obj; 【】当一构造函数执行的时候,this就是我们创建的那个实例; 所有的对象数据类型都是内置Object类的一个实例