在 JavaScript 中的始皇 一文中,笔者有个观点:
Object.prototype 是真正的始皇,任何原型都源自它;而 Function.prototype 是仅次于 Object.prototype 的存在,它是内置构造函数的创建者,任何构造函数都源自它
所以 Function 的原型有一定的重要性,Function(构造函数) 与 Function.prototype(原型)又是相生相伴的关系,从构造函数层面,它已经比 Array、String、Number 等重要了,虽然比不上 Object,但也是仅次于它的存在
不仅如此,函数还能做很多事情。首先,它是个对象,这一知识点我们在 一切皆对象 中解释过,所以它和对象一样,也有属性,也可以赋值给变量。除此之外,函数可以自身当作参数传递,也具有返回值的特性
总之,对象能做的它都能做,它还有自身的特性,能做更多的事情(例如:能作为参数传递,有返回值)
在解释函数的特性之前,先了解下它的属性和方法
看例子说话
function func() {}
console.dir(func)
我们用函数声明的形式创建了一个普通函数 func,打印它。虽然我们没有对其进行任何的赋值操作,但它自身自带了各种属性,很显然,Function 是没有静态方法的,它只有实例属性和实例方法,都继承自 Function.prototype。我们看到函数 func 上有 arguments、caller、length、name ,这些都是继承自 Function.prototype,在 func.__proto__ 中你能找到同样的属性,这其中的秘密是Function.__proto__ === Function.prototype,具体可看 JavaScript 中的始皇 了解
更多信息可以查看MDN
了解 Function 的实例属性和方法后,我们去看看如何创建函数
创建函数有四种方法:函数构建函数、函数声明、函数表达式、箭头函数
// 函数构造函数:最后一个参数为函数逻辑,之前的都是参数
var add = new Function('x', 'y', 'return x + y');
// 函数声明
function add2(x, y) {
return x + y;
}
// 函数表达式
var add3 = function (x, y) {
return x + y;
};
// 箭头函数
var add4 = (x, y) => x + y
这里需要说明的是,在正常开发中,函数构造函数基本用不到。开发中用的比较多的是函数声明、函数表达式、箭头函数,那么三者有什么区别呢?
先对比函数声明和函数表达式
再对比箭头函数与普通函数
创建函数就是如此,创建了如何调用函数呢?
在不同的场景下,调用函数各显不同,以下几种为调用函数的方式
// 作为函数
var func1 = function () {
return 'foo';
};
console.log(func1); // foo
// 作为方法,即对象中的函数被称为方法
var obj1 = {
func2: function () {
return 'bar';
},
};
console.log(obj1.func2()); // bar
// 作为构造函数
function Person() {
this.name = 'johnny'
this.age = 28;
this.gender = 'female';
this.getName = function () {
return this.name;
};
}
var cody = new Cody(); // 调用构造函数
console.log(cody);
// 使用 call/apply 调用
var obj2 = {
sayHello: function () {
console.log(this.name, arguments[0], arguments[1]);
},
};
var johan = { name: 'johan' };
var elaine = { name: 'elaine' };
// 在 johan 对象上调用 sayHello
obj2.sayHello.call(johan, 'foo', 'bar'); // johan, foo, bar
obj2.sayHello.apply(elaine, ['foo', 'bar']); // elaine, foo, bar
// 自调用
(function() {
console.log('自调用函数');
})();
无论是创建函数,还是调用函数,能有什么用,能证明函数是一等公民吗?
接下来,我们来解释为什么说函数是一等公民?
首先,函数是对象,这意味着函数可以存储在一个变量、数组或对象中。其次,因为是对象,所以它也拥有对象的特性,即它拥有属性。除了对象的特征外,作为函数本身,它可以作为参数传递,也可以作为返回值返回。如此,这些因素就构成了函数成为 JavaScript 中的”一等公民“
// 作为变量保存变量、数组、对象
var funcA = function () {} // 作为变量
var funcB = [function(){}] // 作为数组变量
var funcC = { method: function() {} } // 作为对象方法
// 函数也是对象,意味着可以拥有属性
var funcD = function () {}
funcD.name = 'funcD' // 赋值name
console.log(funcD.name) // funcD
// 作为参数
var funcE = function(func) {
func()
}
funcE(function () {
console.log('函数作为参数传递')
})
// 作为函数返回值
var funcF = function (x, y) {
return x + y // 函数特性,有返回值
}
console.log(funF(1,2)) // 3
PS:所谓的一等公民,即 first-class function,也被称为头等函数,维基百科上对其的介绍是:函数可以作为别的函数的参数、函数的返回值,赋值给变量或存储在数据结构中
同理,MDN也是同样介绍
其中函数作为参数传递和有返回值的特性,使其成为函数式编程的基础
因为函数不仅有对象的能力,而且还有参数传递和有返回值的独有特性,所以使得它成为一等公民。不仅如此,函数还有其他的特性
函数作用域:JavaScript 中的作用域分为全局作用域、函数作用域和块级作用域,块级作用域是ES6之后出现的解决变量提升存在变量覆盖、变量污染等设计缺陷而出的特性。在此之前,只有全局作用域和函数作用域,全局只有一个作用域好理解。函数作用域是认识 JavaScript 重要知识点——闭包的基础,有关作用域的知识点,可以看这篇文章——作用域(后续文章更新)
this:this 是什么,在写原型、构造函数时,我们曾经在构造函数中使用过 this,并在 new 实例化它时,说 new 关键字会将构造函数中的 this 指向新对象并执行构造函数中的代码,那么 this 和什么有关呢?
它和作用域有点像,但不完全一致,它是与执行上下文绑定的,我们会先聊 this关键字(后续文章更新) ,再次基础上会衍生出call、apply、bind 三大将(后续文章更新) 。再回头看 执行上下文,不过再聊它之前,先把 词法环境(后续文章更新)讲清楚,之后再说 执行上下文与执行栈(后续文章更新)
讲了作用域、就会衍生出作用域链。讲了this关键字,就会引出执行上下文,两者一结合,就解释了闭包(后续文章更新),闭包是 JavaScript 中的难点。如果说原型是”少女杀手“,那么闭包就是”师母杀手“
函数有多种形式,如IIFE,即 立即执行函数(后续文章更新),为什么它这么做,这么做为了避免变量被污染。而后的 AMD/CMD,ES中的模块化,都是为了让代码能独立不被别的文件影响
总之,函数有很多特性,因为这些特性,函数才能成为在 JavaScript 中叱诧风云的”人物“
我们就函数的属性、方法说起,介绍了 Function 内置的属性和方法,这样是为了方便开发者调用。接着我们介绍如何创建函数,介绍了四种方法,创建了函数就调用函数,分五种情况介绍。最后我们介绍了函数为什么成为一等公民。成为一等公民,首先是因为它是对象,拥有对象的”能力“,其次,它自身有一些特性让其变得独一无二,例如能作为参数传递,有返回值,这两者是函数式编程的基础
你以为函数就这么简单?那你小瞧函数了
函数的特性还有函数作用域,相对全局作用域,块级作用域,函数作用域的实际用处高达90%;还有this,Function 的原型方法中的 call/apply/bind 就是为了修改 this 而存在的,说明修改 this 指向是个高频操作,this 的解释会引出执行上下文,与作用域中的作用域链结合,就能解释闭包行为。闭包又能衍生出词法环境、执行上下文与调用栈、以及闭包的应用防抖与节流、柯里化。垃圾回收机制等等
总之,函数在 JavaScript 的地位是很高的
来自:https://segmentfault.com/a/1190000042516427
inline-blcok元素中间的空白符引起的间隙,处理方法总结包括:改变书写结构、使用font-size:0、使用margin负值、使用letter-spacing或word-spacing、丢失结束标签、W3C推荐 导航方法(兼容IE6等)、YUI的inline-block间隙处理等...
本文实例讲述了JS实现碰撞检测的方法。分享给大家供大家参考,具体如下:一个简单的碰撞检测例子,检测div1是否和div2发生碰撞,当div1碰到div2时,改变div2的颜色
css实现边竖条的多种方式:border、使用伪元素、外 box-shadow、内 box-shadow、drop-shadow、渐变 linearGradient、轮廓 outline、滚动条
记录下与Math有关的常用方法,如:求最大值、最小值等,或者是保留几位数啥的。本文主要介绍了JavaScript中Math对象的方法,具有一定的参考价值,下面跟着小编一起来看下吧
Split是切割字符串的一种方法,该方法主要用于把一个字符串分割成字符串数组。splice()方法向/从数组中添加/删除元素,然后返回被删除的元素组成的数组。slice()方法主要用于截取数组,并返回截取到的新数组。
第一种:获取的时间戳是把毫秒改成000显示,因为这种方式只精确到秒,第二种和第三种是获取了当前毫秒的时间戳。
在web开发中我们经常会遇到页面的一个二级联动技术,二级联动字面解释就是说我在选择一级select不同的option,下面的二级option的属性值在进行相应的变化。
经常会用到原生JS来写前端。。。但是原生JS的一些方法在适应各个浏览器的时候写法有的也不怎么一样的,一下的方法都是包裹在一个EventUtil对象里面的,直接采用对象字面量定义方法了
是通过 js 操作 textarea input 输入框,只能操作输入框,不能操作其它元素。所有的 复制/剪切/粘贴 都是要在选中输入框中的文本之后,才进行操作的。
async函数是Generator 函数的语法糖,async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await,仅此而已。async函数对Generator 函数的改进点有以下几点:
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!