18前端成长日记-函数

142 阅读4分钟

构造函数

专门用来生成实例对象的函数,它是对象的模板。

构造函数有两个特点

  • 函数内部使用了 this 关键字
  • 生成对象的时候,必须使用 new 命令
var UserNumber = function (arguments) {
    'use strict'
    this.toString = '' + arguments
    this.Method = 'Hello World'
}

var a = new UserNumber(null)
a.toString // 'null'
a.Method // 'Hello World'
let 士兵 = function (兵种,血量,攻击力) {
    this.兵种 = 兵种,
    this.血量 = 血量,
    this.攻击力 = 攻击力
}
//prototype 中存士兵的共有属性
士兵.prototype = {
    '移动速度': '10'//移动速度就是士兵的共有属性
}
//利用 士兵 这个构造函数创造一个兵王的 实例
let 兵王 = new 士兵('中国士兵',100000,100000)
// 兵种: "中国士兵", 血量: 100000, 攻击力: 100000

构造函数一般会和原型链以前应用。我们会把对象的共有属性添加到原型中

new的过程成,会生成一个空对象,作为将要返回的对象。并将这个空对象赋值给函数内部的this。如果构造函数内部 reutrn 了一个对象,那么 new 命令就会返回 return 后面的对象。如果 return 后面有 this, 这个 this 是指向构造函数的

function Fn(){
    this.name = '小明'
    return {name: '小王'}
}

// return 了一个对象,所以 new 就会返回 return 后面的对象
let fn = new Fn()
fn.name // 小王

function Fn1(){
    this.name = '小明'
    return 1
}

fn = new Fn1()
fn.name // 小明

如果return中包含this,那么这个this会指向构造函数

function Fn(){
    this.name = '小明'
    return this
}


let fn = new Fn()
fn.name // 小明


function Fn1(){
    this.name = '小明'
    return {name: this.name}
}

fn = new Fn1()
fn.name // 小明

形参,实参

function fn(a,b){ // a,b就是形参
    return a + b
}
fn(1,2) //1,2就是实参

实参可以是任何的数据类型

当一个函数需要传的参数很多时,可以吧参数包装一个成对象传给函数

function fn(options){
    console.log('我是'+options.name+'我今年'+options.age+'我住在'+options.city)
}
fn({
    name: '张三',
    age: 18,
    city: '北京'
})
//我是张三我今年18我住在北京

函数的声明方法

functionvar 类似,它是一种特殊的声明方式,所以 function 也会变量提升

  1. 具名函数
function fn(x,y) {return x + y}

fn.name //'fn'
  1. 匿名函数
var fn 
fn = function (x,y) {return x + y}
fn.name //'fn'
  1. 将具名函数赋值给变量
//这种方法无法用fn来获取函数
var a = function fn(x,y) {return x + y}
fn.name //Uncaught ReferenceError: fn is not defined
a.name //'fn'
  1. window.Function函数
var fn = new Function ('x','y','return x+y')
fn.name //'anonymous'
  1. 箭头函数
var fn = (x,y) => {return x + y}
var fn = (x,y) => x + y
var fn = n => n*n

函数的调用方式

function fn(x,y) {return x + y}

fn(1,2)

fn.call(undefined,1,2)

声明函数后立即执行

(function(){
    var  parent = document.querySelector('#parent')
    console.log(parent)
}).call()
!function(){
    var  parent = document.querySelector('#parent')
    console.log(parent)
}.call()

this

函数都会接受一个隐藏的参数 this ,默认是window; 已方法的形式调用,this 就是调用这个方法对象

箭头函数不会改变 this,外面的 this是什么内部的 this 就是什么 callbindapply,可以改变this

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

let obj = {
    name: '张三',
    age: 18,
    fn: fn
}
obj.fn() // {name: "张三", age: 18, fn: ƒ}
function fn(x,y) {
    console.log(this)
    return x + y 
}
fn.call(undefined,1,2)
//Window{postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window,…}
//3

function fn(x,y) {
    'use strict' //严格模式
    console.log(this)
    return x + y 
}
fn.call(undefined,1,2)
//undefined
//3

function fn() {
    console.log(this)
}
fn.call(1)
//Number {1}

function fn() {
    'use strict'
    console.log(this)
}
fn.call(1)
//1

arguments

数组的参数

function fn(x,y) {
    console.log(arguments)
}

fn.call(undefined,1,2) //1和2 就是 arguments
//Arguments(2)[1, 2, callee: ƒ, Symbol(Symbol.iterator): ƒ]0: 11: 2callee: ƒ fn(x,y)length: 2Symbol(Symbol.iterator): ƒ values()__proto__: Object
//undefined

得到 arguments 长得很像一个数组,但是它的原型链中没有 Array.prototype

作用域

函数内部的代码有自己的影响区域

作用域可以自己定义

函数内的赋值不会影响到函数外的,作用域链可以往上查找

var a = 1
function fn() {
    a = 2
    console.log(a)
}
fn.call() //2 
console.log(a) //1 

上面的例子发现在函数内的赋值并不会对外部的 a 产生影响,这就是因为函数有作用域

var a = 1
function f1(){
    alert(a) 
    var a = 2
}
f1.call() // undefined
var a = 1
function f1(){
    var a = 2
    f2.call()
}
function f2(){
    console.log(a)
}
f1.call() // 1

闭包

如果一个函数,使用了它范围外的变量,那么(这个函数+这个变量)就是闭包

var a = 1

function fn() {
    console.log(a)
}

总结

函数内部声明的变量因为函数作用域的原因,不能被外部访问到。如果想要它被外部访问到可以把这个变量变成全局变量(window)