精华内容
下载资源
问答
  • 下面是文档、工具包和官网(本文只用了其中的p5.min.js) 链接:https://pan.baidu.com/s/1i5D0OpZ 密码:e04v https://p5js.org/ 拟合直线 最终效果 数学公式 ∑ni=0(x−x¯)...

    最小二乘法拟合

    使用工具

    p5.js 是开源的设计师工具,专攻画图
    下面是文档、工具包和官网(本文只用了其中的p5.min.js)
    链接:https://pan.baidu.com/s/1i5D0OpZ 密码:e04v
    https://p5js.org/

    拟合直线

    最终效果

    两个点
    三个点
    多个点

    数学公式

    ∑ i = 0 n ( x − x ‾ ) ( y − y ‾ ) ∑ i = 0 n ( x − x ‾ ) ( x − x ‾ ) \frac{\sum_{i=0}^n (x-\overline x)(y-\overline y)}{\sum_{i=0}^n(x-\overline x)(x-\overline x)} i=0n(xx)(xx)i=0n(xx)(yy)

    代码 JS

    var data=[];//点坐标
    var a=1;//拟合直线的x系数
    var b=0;//拟合直线的常熟b
    /**
     * 初始函数
     */
    function setup() {//p5.js的初始方法
        createCanvas(400,400);
        background(0,3,3);
    }
    /**
     * 一次函数线性回归(系数项和常数项)
     */
    function linearRegression(){
        var xsum=0;//x的多项和
        var ysum=0;//y的多项和
        for(var i=0;i<data.length;i++){
            xsum+=data[i].x;
            ysum+=data[i].y;
        }
        var xmean=xsum/data.length;//x的平均数
        var ymean=ysum/data.length;//y的平均数
        var num=0;//多项式和【(x-x的均值)*(y-y的均值)】
        var den=0;//多项式和【(x-x的均值)*(x-x的均值)】
        for(var i=0;i<data.length;i++){
            var x=data[i].x;
            var y=data[i].y;
            num+=(x-xmean)*(y-ymean);
            den+=(x-xmean)*(x-xmean);
        }
        a=num/den;//y=ax+b 的 系数a
        b=ymean-a*xmean;//y=ax+b 的 系数b
    }
    /**
     * 鼠标点击
     */
    function mousePressed(){
        var x=map(mouseX,0,width,0,100);
        var y=map(mouseY,0,height,100,0);
        var point = createVector(x,y);
        data.push(point);
    }
    /**
     * 画直线
     */
    function drawLine(){
        var x1=0;//得到(x1,y1),(x2,y2),即可画直线
        var x2=100;
        var y1=a*x1+b;
        var y2=a*x2+b;
        x1=map(x1,0,100,0,width);
        x2=map(x2,0,100,0,width);
        y1=map(y1,0,100,height,0);
        y2=map(y2,0,100,height,0);
        stroke(255);
        line(x1,y1,x2,y2);
    }
    /**
     * 绘画(点和线)
     */
    function draw() {
        background(50);
        for(var i=0;i<data.length;i++){
            var x=map(data[i].x,0,100,0,width);
            var y=map(data[i].y,0,100,height,0);
            fill(255,0,0);//设置填充颜色
            stroke(255);//设置边框颜色
            strokeWeight(2);//设置点的宽度
            ellipse(x,y,10,10);//椭圆
        }
        if(data.length>1){
            linearRegression();
            drawLine();
        }
    }
    

    代码 html

    <!DOCTYPE html>
    <html>
      <head>
        <meta name="viewport" width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0>
        <style> body {padding: 0; margin: 0;} </style>
        <script src="libs/p5.min.js"></script>
        <script src="sketch.js"></script>
      </head>
      <body>
      </body>
    </html>
    

    曲线拟合(二次)

    最终效果

    三个点
    四个点
    多个点

    数学公式 这个公式有点复杂 上个截图(注意其中的p(x),α,β,a)

    二次型和多次型的公式是一致的。二次函数拟合做成后可以延伸至多次
    曲线拟合公式
    二次拟合公式

    代码 JS

    var data=[];//点坐标
    /**
     * 初始函数
     */
    function setup() {
        createCanvas(400,400);
        background(0,3,3);
    }
    var alpha0=0;
    var alpha1=0;
    var a0=0;
    var a1=0;
    var a2=0;
    var beta0=0;
    /**
     * 二次函数
     */
    function unLinearRegression(){
        var xsum=0;//x的和
        var ysum=0;//y的和
    
        for(var i=0;i<data.length;i++){
            xsum+=data[i].x;
            ysum+=data[i].y;
        }
        var length=data.length;//p0(x)=1,所以p0(x)的和就是数据长度
        alpha0=xsum/data.length;//α0
        var p1data=[];//p1(x)
        var p1p1sum=0;//p1*p1 多项式的和
        var xp1p1sum=0;//x*p1*p1 多项式的和
        for(var i=0;i<data.length;i++){
            var p1=data[i].x-alpha0;
            p1p1sum+=p1*p1;
            xp1p1sum+=data[i].x*p1*p1;
            p1data.push(p1);
        }
        alpha1=xp1p1sum/p1p1sum;//α1
        beta0=p1p1sum/length;//β0
        var p2data=[];//p2(x)
        var p2p2sum=0;//p2*p2 多项式的和
        var xp2p2sum=0;//x*p2*p2 多项式的和
        for(var i=0;i<data.length;i++){
            var p2=(data[i].x-alpha1)*p1data[i]-beta0;
            p2data.push(p2);
            p2p2sum+=p2*p2;
            xp2p2sum+=data[i].x*p2*p2;
        }
        //var alpha2=xp2p2sum/p2p2sum;
        var fp0=ysum;//y*p0 多项式的和
        var fp1=0;//y*p1 多项式的和
        var fp2=0;//y*p2 多项式的和
        for(var i=0;i<data.length;i++){
            fp1+=data[i].y*p1data[i];
            fp2+=data[i].y*p2data[i];
        }
        a0=fp0/length;//g(x)=a0*p0(x)+a1*p1(x)+a2*p2(x) 二次多项式拟合公式
        a1=fp1/p1p1sum;
        a2=fp2/p2p2sum;
    }
    /**
     * 画曲线
     */
    function drawCurve(){
        var newdata=[];//二次多项式 点数据
        for(var i=0;i<100;i++){//生成100个点画曲线
            var x=i*100;
            var pp1x=x-alpha0;
            var pp2x=(x-alpha1)*(x-alpha0)-beta0;
            var y=(a0+a1*pp1x+a2*pp2x);
            /*var y=x*x+90;*/
            var point=createVector(x,y);
            newdata.push(point);
        }
        //b=x*x;
        var i=0;
        noFill();
        //三个点即可形成一条曲线
        if(i<newdata.length){
            var p1x=newdata[i].x;
            var p1y=newdata[i].y;
            p1x=map(p1x,0,100,0,width);
            p1y=map(p1y,0,100,height,0);
            i++;
            var p2x=newdata[i].x;
            var p2y=newdata[i].y;
            p2x=map(p2x,0,100,0,width);
            p2y=map(p2y,0,100,height,0);
            i++;
            var p3x=newdata[i].x;
            var p3y=newdata[i].y;
            p3x=map(p3x,0,100,0,width);
            p3y=map(p3y,0,100,height,0);
            i++;
    /*      var p4x=newdata[i].x;
            var p4y=newdata[i].y;
            p4x=map(p4x,0,100,0,width);
            p4y=map(p4y,0,100,height,0);
            i++;*/
            var p1 = {x: p1x, y: p1y};
            var p2 = {x: p2x, y: p2y};
            var p3 = {x: p3x, y: p3y};
            //var p4 = {x: p4x, y: p4y};
            noFill();
            stroke(138, 43, 226);//曲线颜色 - 紫罗兰色
            strokeWeight(4);//曲线宽度
            curve(p1.x, p1.y, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y);
        }
    }
    /**
     * 鼠标点击
     */
    function mousePressed(){
        var x=map(mouseX,0,width,0,100);
        var y=map(mouseY,0,height,100,0);
        var point = createVector(x,y);
        data.push(point);
    }
    /**
     * 绘画(点和线)
     */
    function draw() {
        background(50);
        for(var i=0;i<data.length;i++){
            var x=map(data[i].x,0,100,0,width);
            var y=map(data[i].y,0,100,height,0);
            fill(255,0,0);//设置填充颜色
            stroke(255);//设置边框颜色
            strokeWeight(2);//设置点的宽度
            ellipse(x,y,10,10);//椭圆
        }
        if(data.length>2){
            unLinearRegression();
            drawCurve();
        }
    }
    

    代码 HTML 和直线一致

    展开全文
  • 本软件可以根据您的二次函数而画出相应的抛物线,支持多条二次函数画在同一坐标轴上。能显示与坐标轴的交点,并且有动画等功能,是工程、解题的有力帮手。 修复了抛物线消失的bug,支持清除抛物线等。
  • 数学测验在 decartian 坐标系 介绍 这个线性和二次函数评估系统是用简单的 javascript canvas 和 php 构建的 使用 Xampp 进行部署。 支持 MySQL 需要执行sql文件
  • js函数的回调

    万次阅读 多人点赞 2019-07-31 19:09:41
    平常的前端开发工作中,编写js时会有很多地方用到函数的回调。 最简单的例子就是: <script language="javascript" type="text/javascript"> function doSomething(callback) { if(typeof callback == ...

    平常的前端开发工作中,编写js时会有很多地方用到函数的回调。

    最简单的例子就是:

    <script language="javascript" type="text/javascript">
    function doSomething(callback) {
    if(typeof callback == "function") {
    callback();
    }
    } 
    
    function foo() {
    alert("我是回调后执行的函数");
    } 
    
    doSomething(foo); /*正确*/
    doSomething(function(){
    alert("我是回调后执行的函数");
    }); /*正确*/
    doSomething("foo"); /* 这样是不行的,传入的是一个字符串,不是一个函数名 */
    </script>

    以上只能回调没有参数的(除法你事先知道回调的函数的参数),如果函数有未知的函数,就不能如此简单的调用了。

     

    高级方法:

    1、使用javascript的call方法

    function doSomething(callback,arg1,arg2) {
    callback.call(this,arg1,arg2);
    }
    function foo(arg1,arg2) {
    alert(arg1+":"+arg2);
    }
    doSomething(foo,1,2); /* 弹出了1:2 */

     

    2、使用javascript 的 apply方法

     

    function doSomething(callback,args) {
    callback.apply(window,args);
    }
    function foo(arg1,arg2) {
    alert(arg1+":"+arg2);
    }
    doSomething(foo,[1,2,3]); /* 弹出了1:2 */

    可以看成call和apply基本一样,区别就是call只能一个个传参数,apply只能把参数放数组里传进来

    他们的第一个参数都是作用域,比如上面传了this,表示就是和doSomething这个函数一样的作用域,当然你也可以传window,表示整个window的作用域

     

    3、apply的巧妙用法

    apply也可以看作是函数的执行函数,就是用来执行某个函数的函数。所以你会发现,有时候用好apply,有很多原本繁杂的事情会变得如此简单。

    比如数组的push方法使用apply来调用:

    var arr1=[1,3,4];

    var arr2=[3,4,5];

    如果我们要把 arr2展开,然后一个一个追加到arr1中去,最后让arr1=[1,3,4,3,4,5]

    arr1.push(arr2)显然是不行的。 因为这样做会得到[1,3,4,[3,4,5]]

    我们只能用一个循环去一个一个的push(当然也可以用arr1.concat(arr2),但是concat方法并不改变arr1本身)

    var arrLen=arr2.length

    for(var i=0;i<arrLen;i++){

        arr1.push(arr2[i]);

    }

    自从有了Apply,事情就变得如此简单

    Array.prototype.push.apply(arr1,arr2)

    一行代码就解决了,原理能看的出来,Array.prototype.push是指数组的push函数,apply(arr1,arr2)说明arr1是作用域,就等同于是arr1调用了数组的push函数,

    而且arr1的确就是个数组,所以可以调用,arr2表示入参的数组。所以,以上语句等同于:arr1.push(3,4,5)。(push函数支持传递多个入参,这也是这里可以使用apply的前提条件)

    以上语句也可以写成:arr1.push.apply(arr1,arr2); 两者完全等效,因为arr1.push表示arr1的push函数,也就是数组的push函数。

    如果使用call就是这样Array.prototype.push.call(arr1,arr2[0],arr2[1]...),显然还是apply合适。

    要是你还问,那直接用arr1.push(3,4,5)不就行了,那已经暴露了你的智商,arr2又不是不可以变,下次不是[3,4,5]了呢。

     

    还有获取数组中,最大的那个数字,也可以使用apply调用Math.max函数

    var arr1=[1,3,4];

    alert(Math.max.apply(window,arr1)); /* 作用域可以不是window,就算是null都行,Math.max.apply(this,arr1),Math.max.apply(null,arr1) */

     

    4、工作中函数回调的实际例子

    有了上面的基础,就能看的懂工作中封装好的js的回调函数了

    背景:页面A需要使用页面B来选择某个项目,然后带回这个项目的信息给页面A,页面A根据这些信息丰富自己。

    页面A:

    noticeInfo = {
    selectProject: function () {
    var win = newsee.ui.window
    win.show('项目列表', '../Project/ProjectSelectList.html?callback=noticeInfo.setProjectInfo', { size: win.winSizeType.big })
    //在当前页面弹出框,框里面是另一个页面,地址后面带上需要回调的函数名
    //注意这两个页面其实都是在一个页面里面的,并不是像window.open()那样出现了新窗口,所以两个页面的js都是可见的
    },
    setProjectInfo: function (obj) {
    //回调函数,将选择好的项目对象传进来,然后丰富自己的页面
    $('#projectName').val(obj.name)
    $('#projectID').val(obj.id)
    }
    }

    页面B:

    function SelectBack() {
    var callback = newsee.util.url.getQuery('callback'); //获取页面参数callback,这里获取到的是"noticeInfo.setProjectInfo",是个字符串
    var arr = newsee.ui.grid.getSelectedBack('datagrid') //获取选择的项目,这个不用深究
    if (!arr.length) {
    return newsee.ui.window.alert('请选择项目!')
    }
    newsee.util.url.back(callback, arr[0]) //重点来了,这里执行回调,将需要回调的函数名和入参传进来,arr[0]就是选择的项目的对象的数组了(它也是个数组,里面就一个对象)
    }

    newsee.util.url.back函数如下:

    back : function (funcName) {
    // / <param name="funcName" type="String">返回时执行的方法,一般为重新绑定</param>
    
    var isWindow = typeof $$winClose === 'function',// 是否为弹窗
    args // 弹窗返回方法参数
    
    if (isWindow) {// 弹窗的返回方法
    $$winClose()
    
    args = [].slice.call(arguments) //arguments大家应该都知道的吧,它可以用来获取函数的实参,它类似数组又不是数组,这句代码就是把它转换成数组,因为apply的入参需要是个数组才行
    //args现在里面有两个元素,args[0]=callback,就是之前传进来的回调函数名,args[1]=arr[0],就是回调函数的入参
    newsee.callFunc.apply(newsee, args) //执行 newsee.callFunc 函数,作用域就是newsee自己(等同于newsee自己调用callFunc函数),参数是args
    } 
    }

    newsee.callFunc函数如下:

    callFunc: function(funcName, arg) {
    var func = typeof funcName === 'function' ? funcName : this.findItem(window, funcName) //上面我有提到过,doSomething("foo"); 传入的是一个字符串,不是一个函数名,所以无法执行
    //同样的道理,现在funcName=args[0]=callback="noticeInfo.setProjectInfo",是个字符串,不能直接调用apply,需要变成函数
    //这句话就是用来判断funcName是不是一个函数,如果不是,就在window作用域里根据funcName找到这个函数,然后赋给func
    if (typeof func === 'function') {
    //此时func已经是个函数了,就是页面A里定义的noticeInfo.setProjectInfo()
    try {
    return func.apply(window, arg) //执行需回调的函数,作用域依然是window,反正这个函数在window里肯定能找到,参数就是arg=args[1]=arr[0],即之前在页面B获取到的项目对象
    }
    catch (e) {
    console.error(e)
    }
    }
    }

    ok,需回调的函数就这样被执行了,至于怎么根据字符串形式的函数名获取这个函数,看下面。

    //findItem函数如下:
    findItem: function(data, key) {
    // / <summary>获取对象指定键的值</summary>
    if (this.include(data, key)) { //data这里就是传进来的window,注意window就是一个对象,首先判断window对象里是否存在"noticeInfo.setProjectInfo"这个属性
    return eval('data.' + key) //如果存在,就执行"data.noticeInfo.setProjectInfo",这样就获取到了这个函数了。(eval() 函数可计算某个字符串,并执行其中的的 JavaScript 代码)
    }
    }
    //include函数如下:
    include: function(data, key) {
    // / <summary>判断对象是否存在键值</summary>
    if (data == null || typeof data !== 'object' || !key || typeof key !== 'string') {
    return false
    }
    var keys = key.split('.'),
    item = data,
    result = true
    keys.forEach(function(k) {
    if (item != null && typeof item === 'object' && k in item) {
    //依次循环遍历,第一次item = data,那就是window这个对象,k="noticeInfo",window[noticeInfo]是存在的,因为在页面A里定义了noticeInfo这么一个对象
    //第二次循环,item=window.noticeInfo,k="setProjectInfo",window.noticeInfo[setProjectInfo]也是存在的,因为在页面A里也定义了setProjectInfo这么一个函数
    //这里没有第三次循环了,所以最后返回是true,说明window对象里存在"noticeInfo.setProjectInfo"这个属性,接下来使用eval()拿到它即可
    item = item[k]
    } else {
    return result = false
    }
    })
    
    return result
    }

    对eval() 函数也介绍一下:

    eval() 函数可计算某个字符串,并执行其中的的 JavaScript 代码。

    返回值就是通过计算 string 得到的值(如果有的话)。如:

    eval("x=10;y=20;document.write(x*y)") //输出 200

    document.write(eval("2+2")) //输出 4

    var x=10

    document.write(eval(x+17)) //输出 27

    所以上面的eval('data.' + key)就是执行"data.noticeInfo.setProjectInfo"这个字符串,

    因为data在这里就是指window,所以返回值就是window.noticeInfo.setProjectInfo()这个函数

     

    其实可以在简单一点,根本没必要使用eval()来获取这个函数,因为在include函数里,item就已经是window.noticeInfo.setProjectInfo这个对象了,这个对象就是我们想要的函数。

    (在js中函数也是对象,函数名就是这个函数的引用,就和地址差不多)

    既然都拿到这个函数了,直接返回不就行了,所以上面的include()和findItem可以这样简化:

    include: function(data, key) {
    if (data == null || typeof data !== 'object' || !key || typeof key !== 'string') {
    }else{
    var keys = key.split('.'),
    item = data,
    result = true
    keys.forEach(function(k) {
    if (item != null && typeof item === 'object' && k in item) {
    item = item[k]
    } else {
    result = false;
    }
    })
    if(result)
    return item
    }
    },
    findItem: function(data, key) {
    return this.include(data, key)
    }

    经过测试,发现这两个根据字符串形式的函数名获取函数的方法都可以达到一模一样的效果。

    ------------------------------------------------------------------------声明-------------------------------------------------------------
    以上部分是copy别人的,部分是自己的理解!
    本人水平有限,如有不对之处,还望大神指正,谢谢!

    展开全文
  • Js函数

    千次阅读 热门讨论 2021-02-21 13:18:57
    目录JavaScript 函数定义自调用函数箭头函数JavaScript 函数参数参数规则默认参数ES6 函数可以自带参数arguments 对象JavaScript 函数调用this 关键字调用 JavaScript 函数作为一个函数调用函数作为方法调用使用构造...

    JavaScript 函数定义

    JavaScript 使用关键字 function 定义函数。
    函数可以通过声明定义,也可以是一个表达式。
    函数声明

    function functionName(parameters) {
      执行的代码
    }
    

    函数声明后不会立即执行,会在我们需要的时候调用到。

    分号是用来分隔可执行JavaScript语句。

    由于函数声明不是一个可执行语句,所以不以分号结束。

    函数表达式
    JavaScript 函数可以通过一个表达式定义。
    函数表达式可以存储在变量中:

    var x = function (a, b) {return a * b};
    

    在函数表达式存储在变量后,变量也可作为一个函数使用:

    var x = function (a, b) {return a * b};
    var z = x(4, 3);
    

    以上函数实际上是一个 匿名函数 (函数没有名称)。
    函数存储在变量中,不需要函数名称,通常通过变量名来调用。

    上述函数以分号结尾,因为它是一个执行语句。

    Function() 构造函数
    在以上实例中,我们了解到函数通过关键字 function 定义。
    函数同样可以通过内置的 JavaScript 函数构造器(Function())定义。

    var myFunction = function (a, b) {return a * b};
    
    var x = myFunction(4, 3);
    

    在 JavaScript 中,很多时候,你需要避免使用 new 关键字。

    函数提升(Hoisting)
    在之前的教程中我们已经了解了 “hoisting(提升)”。
    提升(Hoisting)是 JavaScript 默认将当前作用域提升到前面去的的行为。
    提升(Hoisting)应用在变量的声明与函数的声明。
    因此,函数可以在声明之前调用:

    myFunction(5);
    
    function myFunction(y) {
        return y * y;
    }
    

    使用表达式定义函数时无法提升。

    自调用函数

    函数表达式可以 “自调用”。
    自调用表达式会自动调用。
    如果表达式后面紧跟 () ,则会自动调用。
    不能自调用声明的函数。
    通过添加括号,来说明它是一个函数表达式:

    以上函数实际上是一个 匿名自我调用的函数 (没有函数名)。

    函数可作为一个值使用

    function myFunction(a, b) {
        return a * b;
    }
    
    var x = myFunction(4, 3);
    

    JavaScript 函数可作为表达式使用:

    function myFunction(a, b) {
        return a * b;
    }
    
    var x = myFunction(4, 3) * 2;
    

    函数是对象
    在 JavaScript 中使用 typeof 操作符判断函数类型将返回 “function” 。
    但是JavaScript 函数描述为一个对象更加准确。
    JavaScript 函数有 属性方法
    arguments.length 属性返回函数调用过程接收到的参数个数:

    toString() 方法将函数作为一个字符串返回:

    函数定义作为对象的属性,称之为对象方法。
    函数如果用于创建新的对象,称之为对象的构造函数。

    箭头函数

    ES6 新增了箭头函数。
    箭头函数表达式的语法比普通函数表达式更简洁。

    (参数1, 参数2,, 参数N) => { 函数声明 }
    
    (参数1, 参数2,, 参数N) => 表达式(单一)
    // 相当于:(参数1, 参数2, …, 参数N) =>{ return 表达式; }
    

    没有参数的函数应该写成一对圆括号:

    () => {函数声明}
    
    • 有的箭头函数都没有自己的 this。 不适合定义一个 对象的方法。
    • 当我们使用箭头函数的时候,箭头函数会默认帮我们绑定外层 this的值,所以在箭头函数中 this 的值和外层的 this 是一样的。
    • 箭头函数是不能提升的,所以需要在使用之前定义。
    • 使用 const比使用 var 更安全,因为函数表达式始终是一个常量。
    • 如果函数部分只是一个语句,则可以省略 return 关键字和大括号{},这样做是一个比较好的习惯:

    JavaScript 函数参数

    JavaScript 函数对参数的值没有进行任何的检查。

    functionName(parameter1, parameter2, parameter3) {
        // 要执行的代码……
    }
    

    函数显式参数在函数定义时列出。
    函数隐式参数在函数调用时传递给函数真正的值。

    参数规则

    JavaScript 函数定义显式参数时没有指定数据类型。
    JavaScript 函数对隐式参数没有进行类型检测。
    JavaScript 函数对隐式参数的个数没有进行检测。

    默认参数

    ES5 中如果函数在调用时未提供隐式参数,参数会默认设置为: undefined
    有时这是可以接受的,但是建议最好为参数设置一个默认值:

    实例(ES5)
    function myFunction(x, y) {
        if (y === undefined) {
              y = 0;
        } 
    }
    

    或者,更简单的方式:

    实例(ES5)
    function myFunction(x, y) {
        y = y || 0;
    }
    

    如果y已经定义 , y || 返回 y, 因为 y 是 true, 否则返回 0, 因为 undefined 为 false。

    如果函数调用时设置了过多的参数,参数将无法被引用,因为无法找到对应的参数名。 只能使用 arguments 对象来调用。

    ES6 函数可以自带参数

    ES6 支持函数带有默认参数,就判断 undefined 和 || 的操作:

    实例(ES6function myFunction(x, y = 10) {
        // 如果不传入参数 y ,则其默认值为 10
        return x + y;
    }
    // 输出 2
    document.getElementById("demo1").innerHTML = myFunction(0, 2) ;
    // 输出 15, y 参数的默认值
    document.getElementById("demo2").innerHTML = myFunction(5);
    

    arguments 对象

    JavaScript 函数有个内置的对象 arguments 对象。
    argument 对象包含了函数调用的参数数组。
    通过这种方式你可以很方便的找到最大的一个参数的值:

    x = findMax(1, 123, 500, 115, 44, 88);
     
    function findMax() {
        var i, max = arguments[0];
        
        if(arguments.length < 2) return max;
     
        for (i = 0; i < arguments.length; i++) {
            if (arguments[i] > max) {
                max = arguments[i];
            }
        }
        return max;
    }
    

    通过值传递参数

    在函数中调用的参数是函数的隐式参数。

    JavaScript 隐式参数通过值来传递:函数仅仅只是获取值。

    如果函数修改参数的值,不会修改显式参数的初始值(在函数外定义)。

    隐式参数的改变在函数外是不可见的。


    通过对象传递参数
    在JavaScript中,可以引用对象的值。
    因此我们在函数内部修改对象的属性就会修改其初始的值。
    修改对象属性可作用于函数外部(全局变量)。
    修改对象属性在函数外是可见的。

    JavaScript 函数调用

    JavaScript 函数有 4 种调用方式。
    每种方式的不同在于 this 的初始化。

    this 关键字

    一般而言,在Javascript中,this指向函数执行时的当前对象。
    注意 this 是保留关键字,你不能修改 this 的值。

    调用 JavaScript 函数

    在之前的章节中我们已经学会了如何创建函数。
    函数中的代码在函数被调用后执行。

    作为一个函数调用

    function myFunction(a, b) {
        return a * b;
    }
    myFunction(10, 2);           // myFunction(10, 2) 返回 20
    

    以上函数不属于任何对象。但是在 JavaScript 中它始终是默认的全局对象。
    在 HTML 中默认的全局对象是 HTML 页面本身,所以函数是属于 HTML 页面。
    在浏览器中的页面对象是浏览器窗口(window 对象)。以上函数会自动变为 window 对象的函数。
    myFunction() 和 window.myFunction() 是一样的:

    function myFunction(a, b) {
        return a * b;
    }
    window.myFunction(10, 2);    // window.myFunction(10, 2) 返回 20
    

    这是调用 JavaScript 函数常用的方法, 但不是良好的编程习惯
    全局变量,方法或函数容易造成命名冲突的bug。

    全局对象
    当函数没有被自身的对象调用时 this 的值就会变成全局对象。
    在 web 浏览器中全局对象是浏览器窗口(window 对象)。
    该实例返回 this 的值是 window 对象:

    function myFunction() {
        return this;
    }
    myFunction();                // 返回 window 对象  [object Window]
    

    函数作为全局对象调用,会使 this 的值成为全局对象。
    使用 window 对象作为一个变量容易造成程序崩溃。

    函数作为方法调用

    在 JavaScript 中你可以将函数定义为对象的方法。
    以下实例创建了一个对象 (myObject), 对象有两个属性 (firstNamelastName), 及一个方法 (fullName):

    var myObject = {
        firstName:"John",
        lastName: "Doe",
        fullName: function () {
            return this.firstName + " " + this.lastName;
        }
    }
    myObject.fullName();         // 返回 "John Doe"
    

    fullName 方法是一个函数。函数属于对象。 myObject 是函数的所有者。
    this对象,拥有 JavaScript 代码。实例中 this 的值为 myObject 对象。
    测试以下!修改 fullName 方法并返回 this 值:

    var myObject = {
        firstName:"John",
        lastName: "Doe",
        fullName: function () {
            return this;
        }
    }
    myObject.fullName();          // 返回 [object Object] (所有者对象)
    

    函数作为对象方法调用,会使得 this 的值成为对象本身。

    使用构造函数调用函数

    如果函数调用前使用了 new 关键字, 则是调用了构造函数。
    这看起来就像创建了新的函数,但实际上 JavaScript 函数是重新创建的对象:

    // 构造函数:
    function myFunction(arg1, arg2) {
        this.firstName = arg1;
        this.lastName  = arg2;
    }
     
    // This    creates a new object
    var x = new myFunction("John","Doe");
    x.firstName;                             // 返回 "John"
    

    构造函数的调用会创建一个新的对象。新对象会继承构造函数的属性和方法。

    构造函数中 this 关键字没有任何的值。
    this 的值在函数调用实例化对象(new object)时创建。

    作为函数方法调用函数

    在 JavaScript 中, 函数是对象。JavaScript 函数有它的属性和方法。
    call()apply() 是预定义的函数方法。 两个方法可用于调用函数,两个方法的第一个参数必须是对象本身。

    function myFunction(a, b) {
        return a * b;
    }
    myObject = myFunction.call(myObject, 10, 2);     // 返回 20
    
    function myFunction(a, b) {
        return a * b;
    }
    myArray = [10, 2];
    myObject = myFunction.apply(myObject, myArray);  // 返回 20
    

    两个方法都使用了对象本身作为第一个参数。 两者的区别在于第二个参数: apply传入的是一个参数数组,也就是将多个参数组合成为一个数组传入,而call则作为call的参数传入(从第二个参数开始)。
    在 JavaScript 严格模式(strict mode)下, 在调用函数时第一个参数会成为 this 的值, 即使该参数不是一个对象。
    在 JavaScript 非严格模式(non-strict mode)下, 如果第一个参数的值是 null 或 undefined, 它将使用全局对象替代。

    通过 call() 或 apply() 方法你可以设置 this 的值, 且作为已存在对象的新方法调用。

    this 是 JavaScript 语言的一个关键字。
    它代表函数运行时,自动生成的一个内部对象,只能在函数内部使用。比如:

    function test() {
        this.x = 1;
    }
    

    随着函数使用场合的不同,this 的值会发生变化。但是有一个总的原则,那就是this指的是,调用函数的那个对象。

    作为函数方法调用函数时,此函数执行了相当于 java 中静态函数的功能。

    <script>
    var myObject, myArray;
    myObject={
        name: "hahaha ",
        hsk: "en"
    };
    function myFunction(a, b) {
        alert(this);
        return this.name +this.hsk;
    }
    myArray = [10, 2]
    myObject = myFunction.apply(myObject, myArray);       
    document.getElementById("demo").innerHTML = myObject; 
    </script>
    

    可以用的频率较高的函数作这样的设置,为对象执行相关操作。

    JavaScript 闭包

    JavaScript 变量可以是局部变量或全局变量。
    私有变量可以用到闭包。

    全局变量

    函数可以访问由函数内部定义的变量,如:

    function myFunction() {
        var a = 4;
        return a * a;
    }
    

    函数也可以访问函数外部定义的变量,如:

    var a = 4;
    function myFunction() {
        return a * a;
    }
    

    后面一个实例中, a 是一个 全局 变量。
    在web页面中全局变量属于 window 对象。
    全局变量可应用于页面上的所有脚本。
    在第一个实例中, a 是一个 局部 变量。
    局部变量只能用于定义它函数内部。对于其他的函数或脚本代码是不可用的。
    全局和局部变量即便名称相同,它们也是两个不同的变量。修改其中一个,不会影响另一个的值。

    变量声明时如果不使用 var 关键字,那么它就是一个全局变量,即便它在函数内定义。

    变量生命周期
    全局变量的作用域是全局性的,即在整个JavaScript程序中,全局变量处处都在。
    而在函数内部声明的变量,只在函数内部起作用。这些变量是局部变量,作用域是局部性的;函数的参数也是局部性的,只在函数内部起作用。

    计数器困境
    设想下如果你想统计一些数值,且该计数器在所有函数中都是可用的。
    你可以使用全局变量,函数设置计数器递增:

    var counter = 0;
     
    function add() {
       return counter += 1;
    }
     
    add();
    add();
    add();
     
    // 计数器现在为 3
    

    计数器数值在执行 add() 函数时发生变化。
    但问题来了,页面上的任何脚本都能改变计数器,即便没有调用 add() 函数。
    如果我在函数内声明计数器,如果没有调用函数将无法修改计数器的值:

    function add() {
        var counter = 0;
        return counter += 1;
    }
     
    add();
    add();
    add();
     
    // 本意是想输出 3, 但事与愿违,输出的都是 1 !
    

    以上代码将无法正确输出,每次我调用 add() 函数,计数器都会设置为 1。

    JavaScript 内嵌函数可以解决该问题。


    JavaScript 内嵌函数

    所有函数都能访问全局变量。
    实际上,在 JavaScript 中,所有函数都能访问它们上一层的作用域。
    JavaScript 支持嵌套函数。嵌套函数可以访问上一层的函数变量。
    该实例中,内嵌函数 plus() 可以访问父函数的 counter 变量:

    function add() {
        var counter = 0;
        function plus() {counter += 1;}
        plus();    
        return counter; 
    }
    

    如果我们能在外部访问 plus() 函数,这样就能解决计数器的困境。
    我们同样需要确保 counter = 0 只执行一次。
    我们需要闭包。

    JavaScript 闭包

    还记得函数自我调用吗?该函数会做什么?

    var add = (function () {
        var counter = 0;
        return function () {return counter += 1;}
    })();
     
    add();
    add();
    add();
     
    // 计数器为 3
    

    实例解析

    变量 add 指定了函数自我调用的返回字值。
    自我调用函数只执行一次。设置计数器为 0。并返回函数表达式。
    add变量可以作为一个函数使用。非常棒的部分是它可以访问函数上一层作用域的计数器。
    这个叫作 JavaScript 闭包。它使得函数拥有私有变量变成可能。
    计数器受匿名函数的作用域保护,只能通过 add 方法修改。

    闭包是一种保护私有变量的机制,在函数执行时形成私有的作用域,保护里面的私有变量不受外界干扰。直观的说就是形成一个不销毁的栈环境。

    博客参考

    JS闭包的理解

    闭包,看这一篇就够了——带你看透闭包的本质,百发百中

    展开全文
  • JavaScript函数 JavaScript函数式编程语言,在JavaScript脚本种可以随处看到函数函数构成了JavaScript源码的主体。...//方式:匿名函数 var f = function(){ //函数体 } 命名函数的方法也被称为...

    JavaScript函数

    JavaScript是函数式编程语言,在JavaScript脚本种可以随处看到函数,函数构成了JavaScript源码的主体。

    定义函数

    定义函数的方法有两种:

    • 使用function语句声明函数
    //方式一:命名函数
    function f(){
    	//函数体
    }
    
    //方式二:匿名函数
    var f = function(){
    	//函数体
    }
    

    命名函数的方法也被称为声明式函数,而匿名函数的方法也被称为引用式函数或者函数表达式,即把函数看做一个复杂的表达式,并把表达式赋予给变量。

    • 通过Function对象来构造函数
    var function_name = new Function(arg1, arg2, ..., argN, function_body)
    

    在上面语法形式中,每个arg都是一个函数参数,最后一个参数是函数主体(要执行的代码)。Function()所有参数必须是字符串。

    示例:

    <script>
    	var say = new Function("name","say","document.write('<h1>' + name + ' : ' + say + '</h1>');");
    	say("tom", "Hi!");
    </script>
    

    在这里插入图片描述

    函数调用

    调用函数使用小括号运算符来实现。在括号运算符内部可以包含多个参数列表,参数之间通过逗号进行分隔。

    示例:

    function f(){
    	return "hello world!";
    }
    document.write(f());  //调用函数,并输出返回值
    

    注意:

    • 一个函数可以包含多个return语句,但是在调用函数时只有第一个return语句被执行,且该return语句后面的表达式的值作为函数的的返回值被返回,return语句后面的代码将被忽略。
    • 函数的返回值没有类型限制,它可以返回任意类型的值。
    • 函数调用的方法还有new运算符、call或apply动态调用等方法。

    函数参数

    参数可以分为两种:形参和实参

    • 形参:在定义函数时,传递给函数的参数,被称为形参,即形式上参数
    • 实参:当函数被调用时,传给函数的参数,这些参数被称为实参

    示例:a,b为形参,23,24为实参

    function add(a,b){
    	return a + b;
    }
    alert(add(12,34));
    

    一般情况下,函数的形参和实参个数是相等的,但是JavaScript没有规定两者必须相等。如果形参数大于实参数,则多出的形参值为undefined;相反如果实参大于形参数,则多出的实参就无法被形参变量访问,从而被忽略掉。

    示例:

    function add(a, b){
    	return a + b;
    }
    alert(add(2)); //返回undefined与2相加的值,即为NaN
    

    JavaScript定义了arguments对象,例用该对象可以快速操纵函数的实质。使用arguments.length可以获取函数实参的个数,使用数组下表(arguments[n])可以获取实际传递给含食宿的每个参数。

    示例:

    <script>
    	function add(a, b){
    		if(add.length != arguments.length) //检测形参和实参是否一致
    			throw new Error("实参与形参不一致,请重新调用函数!");
    		else	
    			return a + b;
    	}
    	try{
    		alert(add(2));//尝试调用函数
    	}catch(e){
    		alert(e.message);//捕获异常信息
    	}
    </script>
    

    在这里插入图片描述

    匿名函数

    匿名函数就是没有名称的函数,它相当于一个复杂的表达式。当只需要一次性使用函数时,使用匿名函数会更加有效率。

    示例:匿名函数被调用之后,被赋予给变量z。

    var z = function(x, y){
    	return (x + y) / 2;
    }(23, 35);
    

    函数作为值

    函数实际也是一种结构复杂的数据,因此可以把它作为值赋给其它变量

    示例:

    var a = function(x, y){
    	return (x + y) / 2;
    }
    alert(a(12, 33));//返回22.5
    

    函数作为参数

    函数作为值可以进行传递,因此可以把函数作为参数传递给另一个函数,也可以作为返回值。
    示例:

    var a = function(f, x, y){
    	return f(x, y);
    };
    var b = function(x, y){
    	return x + y;
    };
    alert( a(b, 3, 4) );
    

    函数作为表达式

    函数既然可以当作值来使用,因此也可以参与到表达式运算中。
    示例:

    var a = function(x){
    	alert(x);
    }
    a(50);//提示为50
    
    //针对上面的写法,可以直接使用表达式来编写:
    (function(x){
    	alert(x);
    })(50);//提示为50
    

    闭包函数

    闭包函数是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。
    闭包函数就是外部函数被调用后,它的变量不会消失,仍然被内部函数所使用,而且所有的内部函数都拥有对外部函数的访问权限。

    示例:定义一个函数a,该函数包含一个私有函数b。内部函数b把自身参数m递加给外层函数的私有变量n上,然后返回n的值。外层函数a的返回值为内部函数b,从而形成了一种内层引用外层的闭包关系,于是外层函数就是一个典型的闭包函数

    <script>
    	function a(){				//外层函数,闭包函数
    		var n = 0;				//私有变量
    		function b(m){			//内部函数,私有函数
    			n = n + m;			//递加上级私有变量的值
    			return n;			//返回改变后的值
    		}
    		return b;				//返回私有函数
    	}
    	var b = a();				//调用外层函数,返回内部函数
    	document.write(b(3));		//输出3
    	document.write("<br>");
    	document.write(b(3));		//输出6
    	document.write("<br>");
    	document.write(b(3));		//输出9
    	document.write("<br>");
    	document.write(b(3));		//输出12
    </script>
    

    在这里插入图片描述

    这样当在全局作用域中反复调用内部函数时,将会不断把参数值递加给外层函数的私有变量n身上,形成闭包对外部函数的私有变量长时保护作用。

    展开全文
  • JavaScript 函数

    2016-05-12 12:04:22
    一、JavaScript函数的分类  1、自定义函数(我们自己编写的函数),如:function ...函数的调用方式  1、普通调用:functionName(实际参数...)  2、通过指向函数的变量去调用:  var myVar=函数名;  myVar(实
  • VC与JavaScript交互() ———— 调用JS函数

    万次阅读 多人点赞 2014-01-18 15:35:48
    VC调用无参JS函数 VC调用有参JS函数 VC传递数据给JS函数 JS函数返回一个值给VC JS函数返回多个值给VC
  • JS函数

    2016-09-18 13:49:32
    来源《JavaScript权威指南》 (1)定义一,可多执行。 (2)函数每次调用时还会拥有一个值——this关键字的值——本次调用的上下文。 (3)如果函数作为一个对象的属性,那么他就是对象的方法。通过...
  • JavaScript中的函数

    千次阅读 多人点赞 2019-10-26 14:20:42
    JavaScript函数 什么是函数呢? 概念:函数是由事件驱动的或者当他被调用时可执行的可重复使用的代码块。 函数的定义(创建) 定义分为两种:声明式和创建式。 通过关键字function声明; 通过变量赋值(未命名函数...
  • [js点滴]JavaScript关于函数总结

    千次阅读 2016-10-26 22:16:59
    函数的概念 函数就是实现某一功能的代码片段. 2.函数的分类 a.预定义函数(系统函数) b.自定义函数 函数又称之为方法 3.函数定义 function 函数名(参数1,参数2,参数3,...){ 函数主体 } 注意两点: a....
  • 种实现惰性载入的方式是在声明函数时就制定适当的函数,这样,第一调用函数时就不会损失性能了,而在代码首次加载时会损失一点儿性能。 载入方式一 var flag = 1; function test1() { if(typeof flag === '...
  • JavaScript回调函数

    千次阅读 2015-06-18 10:30:34
    JavaScript API里这样解释:A callback is a function that is passed as an argument to another function and is executed after its parent function has completed. (回调是一个函数作为参数传递给另一个函数,...
  • 简单函数binaryInsert(array, value, comparator) ,可为javascript中的排序数组提供进制插入功能。 这主要用于较大的阵列,可以在查看性能提升。 进制插入为O(log(n))而Javascript的.sort() (使用quicksort或...
  • javascript自执行函数

    千次阅读 2015-12-13 10:49:53
    javascript自执行函数又被称为立即调用函数,下面是其用法、作用和理解
  • 标签打印机,二维码打印机二次开发函数库使用说明,内有各参数的详细意思和使用方法。
  • js 立即执行函数

    万次阅读 2018-10-09 20:59:11
    立即执行函数 目录 立即执行函数 作用 参数 返回值 立即执行函数 立即执行函数模式是一种语法,可以让你的函数在定义后立即被执行。 立即执行函数的组成 定义一个函数 将整个函数包裹在一对括号中 将函数声明...
  • js之防抖函数

    千次阅读 多人点赞 2020-09-14 22:13:40
    这样第一次到第二次触发事件就经历了5秒,极大的减轻了服务器的压力 先来认识防抖函数的使用: 防抖函数实际上已经封装好了,我们只需要用cdn引入就可以进行使用了,但是我们依然要明白其中的原理! <!D.
  • JavaScript入门学习总结1. 什么是 JavaScript2. JavaScript 的特点3. JS的使用编写位置基本语法变量打印变量数据...JavaScript(简称"JS")是一种具有函数优先的轻量级,解释型或即时编译型的编程语言。 2. JavaScrip
  • JS回调函数——简单易懂有实例

    万次阅读 多人点赞 2018-05-11 17:33:02
    初学js的时候,被回调函数搞得很晕,现在回过头来总结一下什么是回调函数。什么是JS?(点击查看) 下面先看看标准的解释: <script language="javascript"> 02 function SortNumber( obj, func ) // ...
  • javascript函数 匿名函数 立即调用

    千次阅读 2013-09-30 21:20:10
    1.函数的返回值: function add(a, b ) { return a + b; } 函数有返回值,当没有...当传递参数值时,如果忘记了给这个参数传递值,javascript会给参数自动赋值undefined。 exp: function add(a, b) { return
  • JS定时器和函数

    千次阅读 2018-11-26 22:14:55
    启动单定时器:setTimeout(第一个参数是多少毫秒之后要调用的回调函数,第个参数是毫秒,1000ms等于1s) &amp;lt;script&amp;gt; setTimeout(function(){ document.write(&quot;2秒之后调用回调...
  • [js点滴]js函数与闭包函数详解

    千次阅读 2016-10-18 23:10:13
    1、匿名函数函数JavaScript中最灵活的一种对象,这里只是讲解其匿名函数的用途。匿名函数:就是没有函数名的函数。1.1 函数的定义,首先简单介绍一下函数的定义,大致可分为三种方式第一种:这也是最常规的一种 ...
  • vue导出js中的函数_js中的函数

    千次阅读 2020-10-12 01:38:40
    vue导出js中的函数In JavaScript, we have got four major things to do:-在JavaScript中,我们要做四件事: To Store values. 存储值。 To Store a series of steps. 存储一系列步骤。 To make decisions. 做出决定...
  • js之惰性函数

    千次阅读 2016-02-01 12:04:41
    利用函数的惰性载入提高javascript代码性能 在javascript代码中,因为各浏览器之间的行为的差异,我们经常会在函数中包含了大量的if语句,以检查浏览器特性,解决不同浏览器的兼容问题。例如,我们最常见的为...
  • JS函数详解

    千次阅读 多人点赞 2019-07-10 22:56:56
    目录 1.函数概念,声明及调用 2.函数表达式(匿名函数) 3.函数传参 4.修改input的值 5.函数的不定参(可变...8.JS预解析机制(变量提升Hoisting) 9.作用域 10.window 11.全局污染(命名冲突问题) 12.作...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 305,336
精华内容 122,134
关键字:

js二次函数