zoukankan      html  css  js  c++  java
  • 原型和闭包

    原型和闭包

    一切皆对象

    一切皆对象(类型值除外)

    undefined, number, string, boolean属于简单的值类型

    函数、数组、对象、new Number(10)都是对象。他们都是引用类型

    Null是基本数据类型,不是引用数据类型
    基本数据类型的值就是它本身的值,引用数据类型是存放的对这个对象引用的指针,Null本身的值就是Null,所以不是引用类型

    不同的对象在底层都表示为二进制,在 JavaScript 中二进制前三位都为 0 的话会被判
    断为 object 类型, null 的二进制表示是全 0,自然前三位也是 0,所以执行 typeof 时会返回“ object ”。

    http://www.cnblogs.com/xiaoheimiaoer/p/4572558.html

    判断值类型的类型用typeof,引用类型的类型用instanceof

    javascript为弱类型,里一切皆是对象,对象里面都是属性,而它的方法也是一种属性,用键值对的形式来表示,且javascript中的对象可以随意扩展属性,没有class的约束。

    简单示例

    var a1={
    	b:10,
    	c:function(n){
    	alert(this.a+n);
    	},
    	d:{car:"000000",long:"五十"}
    };
    

    虽然函数是一种对象,但函数和对象那个之间更像是一种相互生成的关系

    对象都由函数来创建,我们平时所写的var let等其实是一种“语法糖”其本质还是函数

    prototype原型

    每一个函数都有一个属性叫prototype

    prototype的属性值是一个对象,只有一个默认的叫constructor属性,指向函数本身,而还我们可以自己采用自定义的形式在prototype中新增自己的属性

    function F1(){}
    F1.prototype.age="1982";
    F1.prototype.sex=function(){
        return "man";
    };
    

    而这样做的作用就要联系到jQuery了

    var $("div");
    $div.attr('myAge','18');
    

    上面代码中,$('div')返回的是一个对象,而对象被函数创建的而他的实现过程如下

    myjQuery.prototype.attr=function(){
        
    };
    $('div')=new myjQuery();
    

    其本质就是

    function F1(){}
    F1.prototype.age="1982";
    F1.prototype.sex=function(){
        return "man";
    };
    var f2=new F1();
    console.log(f2.age);
    console.log(f2.sex());
    

    F1是一个函数,f2对象是从F1函数new出来的,这样f2对象就可以调用F1.prototype中的属性。

    因为每个对象都有一个隐藏的属性——“proto”,这个属性引用了创建这个对象的函数的prototype。即:

    f2.__proto__ === F1.prototype
    

    这里的"proto_"成为“隐式原型”

    __ proto__ 原型

    每个函数function都有一个prototype,即原型。同时每个对象都有一个__ proto__

    其指向创建该对象的函数的prototype

    个__ proto __是一个隐藏的属性,javascript不希望开发者用到这个属性值,有的低版本浏览器甚至不支持这个属性值

    自定义函数的prototype都是被Object创建,所以它的_ _proto__指向的就是Object.prototype

    但是Object.prototype确实一个特例——它的__ proto__指向的是null,切记切记

    函数也有原型

    function fn(x,y){
    	return x+y;
    };
    console.log(fn(10,20));
    
    var f1= new Function("x","y","return x+y;");
    console.log(f1(8,7));
    

    第二种为new Function仅作理解使用,Function作为函数,也是一种对象,所以也有 __ proto__ 属性,而函数本身是被Function创建,所以Function是被自身创建,他的 __ proto __指向了自身的Prototype。

    同理Function.prototype指向的对象,它的__ proto __也指向Object.prototype

    instanceof

    instanceof 用于对引用类型的判断img

    Instanceof的判断队则是:

    function Foo(){}
    var f1=new Foo();
    
    console.log(f1 instanceof Foo);//true
    console.log(f1 instanceof Object);//true
    

    设第一个变量为A,设第二个函数为B

    沿着A的__ proto__这条线来找,同时沿着B的prototype这条线来找,如果两条线能找到同一个引用,即同一个对象,那么就返回true。如果找到终点还未重合,则返回false

    将前面的整合为整体如下图,通过此图,可以捋清为何返回值为true了

    img

    其实instanceof表示的就是一种继承关系,或者原型链的结构

    继承

    javascript中的继承是通过原型链来体现的

    js是原型继承,C#是类型继承。
    原型继承比类型继承更加灵活,但是又不如类型继承可控

    function foo(){}
    var f1=new foo();
    
    f1.a=10;
    
    Foo.prototype.a=100;
    Fpp.prototype.b=200;
    
    console.log(f1.a);//10
    console.log(f1.b);//200
    

    f1是Foo函数new出来的对象f1.a是f1对象的基本属性而非。b从Foo.prototype得来

    f1.__ proto __指向的是Foo.prototype

    **访问一个对象的属性时,先在基本属性中查找,如果没有,再沿着__ proto__这条链向上找,这就是原型链 **

    img

    访问f1.b时,f1的基本属性中没有b,于是沿着__ proto__找到了Foo.prototype.b

    可使用hasOwnProperty区分一个属性是基本属性还是原型

    原型的灵活性

    对象属性可以随时改动

    在对象或函数new出来后可以随时加属性

    继承方法不合适也可以随时修改

    缺少你所要用的方法时,可以随时去创建

    执行上下文

    • 变量、函数表达式——变量声明,默认赋值为undefined;
    • this——赋值;
    • 函数声明——赋值;

    这三种数据的准备情况我们称之为“执行上下文”或者“执行上下文环境”。

    函数每被调用一次,都会产生一个新的执行上下文环境。因为不同的调用可能就会有不同的参数

    另外一点不同在于,函数在定义的时候(不是调用的时候),就已经确定了函数体内部自由变量的作用域

    大白话理解:在执行代码之前,把将要用到的所有的变量都事先拿出来,有的直接赋值了,有的先用undefined占个空

    了解了执行上下文环境中的数据信息,你就不用再去死记硬背那些可恶的面试题了

    this

    ​ 在函数中this到底取何值,是在函数真正被调用执行的时候确定的,函数定义的时候确定不了,因为this的取值是执行上下文环境的一部分,每次调用函数,都会产生一个新的执行上下文环境。

    1. 构造函数

      所谓构造函数就是用来new对象的函数。其实严格来说,所有的函数都可以new一个对象,但是有些函数的定义是为了new一个对象,而有些函数则不是。另外注意,构造函数的函数名第一个字母大写(规则约定)

    2. 函数作为对象的一个属性

      如果函数作为对象的一个属性时,并且作为对象的一个属性被调用时,函数中的this指向该对象

    3. 函数用call或者apply调用

      当一个函数被call和apply调用时,this的值就取传入的对象的值。

    4. 全局 & 调用普通函数

      全局环境下,this永远是window

      普通函数在调用时,其中的this也都是window

    其实,不仅仅是构造函数的prototype,即便是在整个原型链中,this代表的也都是当前对象的值。

    执行上下文栈

    ​ 执行全局代码时,会产生一个执行上下文环境,每次调用函数都又会产生执行上下文环境。当函数调用完成时,这个上下文环境以及其中的数据都会被消除,再重新回到全局上下文环境。处于活动状态的执行上下文环境只有一个。

    其实这是一个压栈出栈的过程——执行上下文栈img

    作用域

    通常大家认为“javascript没有块级作用域”。所谓“块”,就是大括号“{}”中间的语句

    javascript除了全局作用域之外,只有函数可以创建的作用域。

    ​ 所以,我们在声明变量时,全局代码要在代码前端声明,函数中要在函数体一开始就声明好。除了这两个地方,其他地方都不要出现变量声明。而且建议用“单var”形式

    作用域有上下级的关系,上下级关系的确定就看函数是在哪个作用域下创建的

    作用域最大的用处就是隔离变量,不同作用域下同名变量不会有冲突

    作用域在函数定义时就已经确定了。而不是在函数调用时确定

    ​ 作用域只是一个“地盘”,一个抽象的概念,其中没有变量。要通过作用域对应的执行上下文环境来获取变量的值。同一个作用域下,不同的调用会产生不同的执行上下文环境,继而产生不同的变量的值。所以,作用域中变量的值是在执行过程中产生的确定的,而作用域却是在函数创建时就确定了。

    所以,如果要查找一个作用域下某个变量的值,就需要找到这个作用域对应的执行上下文环境,再在其中寻找变量的值

    自由变量到作用域链

    将变量在作用域外声明在作用域中调用的变量为自由变量

    要到创建这个函数的那个作用域中取值——是“创建”,而不是“调用”,无论函数将在哪里调用

    闭包

    闭包,可理解为:函数作为返回值,函数作为参数传递

    有些情况下函数在被调用完后其上下文环境不会被销毁,如返回值唯一个函数,函数的特别之处在于可以创建一个独立的作用域

    使用闭包会增加内容开销,只有在所有闭包相关作用域执行完毕后才会销毁

    图片来源于网络

  • 相关阅读:
    I2S波形解析
    F407整点原子I2C波形解码
    WAVE格式文件说明
    ADC结构体初始化成员
    这次,我是真的想吐槽MDK
    I2S源程序(正点原子F407探索者)
    强制类型转换
    嵌套结构体的初始化
    lua 元方法 __index
    lua pairs 与 ipairs
  • 原文地址:https://www.cnblogs.com/baiyang2292/p/11175619.html
Copyright © 2011-2022 走看看