JavaScript functions, closures, prototypes, object-oriented assertions
The core of the unit test framework is the assertion method, usually called assert ().
The method typically receives a value-the value that needs to be asserted, and a description that represents the purpose of the assertion.
If the value executes the result of true, the assertion passes;
Otherwise, the assertion will be considered a failure.
The relevant information is usually recorded with a corresponding Pass/fail (fail) tag;
function assert(value, desc) { let li = document.createElement('li'); li.className = value ? 'pass' : 'fail'; li.appendChild(document.createTextNode(desc)); document.getElementById('results').appendChild(li);}// 断言函数function assert(value, desc) { if (value) { console.log(`\033[32m ${desc} \033[0m`); // 断言通过 绿色字体 } else { console.log(`\033[31m ${desc} \033[0m`); // 断言失败 红色字体 }}
Function
JavaScript是一门函数式语言
在JavaScript中,函数是第一型对象。函数可以共处,可以视作为其他任意类型的对象。就像普通的JavaScript数据类型,,函数可以被任意变量进行引用,或声明成对象字面量,甚至可以将其作为函数参数进行传递。
函数是第一型对象
- Can be created by the literal amount.
- You can assign properties to variables, arrays, or other objects.
- Can be passed as a parameter to a function.
- Can be returned as a function's return value.
- You can have properties that are dynamically created and assigned values.
命名一个函数时,该名称在整个函数声明范围内是有效的。如果函数声明在顶层,window对象上的同名属性则会引用到该函数。
所有的函数都有一个name属性,该属性保存的是该函数名称的字符串。匿名函数的name属性值为空。
在JavaScript中,作用域是由function进行声明的,而不是代码块。声明的作用域创建于代码块,但不是终结于代码块(其他语言是终结于代码块的)
if (window) { var x = 123;}alert(x);执行代码后,会弹出123,是因为JavaScript在大括号关闭处并没有终止其作用域。
变量声明的作用域开始于声明的地方,结束于函数的结尾,与代码嵌套无关。
命名函数的作用域是指声明该函数的整个函数范围,与代码嵌套无关;
对于作用域声明,全局上下文就像一个包含页面所有代码的超大型函数。
所有的函数调用都会传递两个隐式参数:argument和this
Called as a function
If a number is not invoked as a method, a constructor, or through apply () or call (), it is considered to be called as a function.
function ninja() {};ninja()var samurai = function() {};samurai()
以这种方式调用时,函数的上下文是全局上下文---window对象。
Called as a method
When a function is assigned to a property of an object and is invoked using this property that references the function, the function is invoked as a method of that object.
var 0 = {};o.whatever = function() {};o.whatever();
将函数作为对象的一个方法进行调用时,该对象就变成了函数上下文,并且在函数内部可以以this参数的形式进行访问。
Called as a constructor
function call Mode differences
函数调用方式之间点主要差异是:作为this参数传递给执行函数的上下文对象之间点区别。
- As a method invocation, the context is the owner of the method;
- Called as a global function, the context is always window (that is, the function is a method of window).
- Called as a constructor, whose context object is the newly created object instance.
Use the Apply () and call () methods
通过函数的apply()方法来调用函数,需要给apply()传入两个参数:一个是函数上下文的对象,另一个是作为函数参数所组成的数组;
通过函数的call()方法来调用函数,需要给call()传入两个参数:一个是函数上下文的对象,另一个是作为函数参数的参数列表,而不是单个数组;
function juggle() { var result = 0; for (var n = 0; n < arguments.length; n++) { result += arguments[n] } this.result = result;}var ninja1 = {};var ninja2 = {};juggle.apply(ninja1, [1,2,3,4]);juggle.call(ninja2, 5,6,7,8)assert(ninja1.result === 10, 'juggled via apply');assert(ninja2.result === 26, 'juggled via call');
使用apply()和call()可以选择任意对象作为函数上下文;
Function Summary
- function is the first type object;
- Created by the literal amount.
- Assigns a value to a variable or property.
- Passed as a parameter.
- Returned as the result of the function.
- Owns properties and methods.
- The function is created by the literal, and its name is optional.
- During the page life cycle, the browser can invoke functions as various types of event handlers.
- The scope of the variable starts at the declaration and ends at the end of the function, which crosses the domain boundary (for example: curly braces)
- An intrinsic function is available (lifted) anywhere in the current function, even if it is referenced in advance.
- The length of a function's formal parameter list and the actual argument list can be different.
- Unassigned parameters are set to undefined.
- The extra parameter is not bound to the parameter name.
- Each function call will pass in two implicit arguments.
- Arguments, the actual passed-in parameter collection.
- This, as the object reference for the function context.
- function calls can be made in different ways, and different invocation mechanisms determine the different function contexts.
- When called as a normal function, its context is a Global object (window).
- When invoked as a method, its context is the object that owns the method.
- When invoked as a constructor, its context is the newly allocated object instance.
- The context can be set to any value when called by the function's apply () or call () method.
anonymous functions
为了不让不必要的函数名称污染全局命名空间,可以创建大量的小型函数进行传递,而不是创建包含大量命令语句的大型函数。
Recursive
Closed Package
var outerValue = 'ninja';var later;function outerFunction() { // 该变量的作用域限制在该函数内部,并且在函数外部访问不到; var innerValue = 'samurai'; // 在外部函数内,声明一个内部函数。 // 注意:声明该函数时,innerValue是在作用域内的 function innerFunction() { assert(outerValue, 'I can see the ninja'); assert(innerValue, 'I can see the samurai'); // 将内部函数引用到later变量上,由于later在全局作用域内,所以可以对它进行调用。 later = innerFunction; }}// 调用外部函数,将会声明内部函数,并将内部函数赋值给later变量。outerFunction();// 通过later调用内部函数。// 我们不能直接调用内部函数,因为它的作用域(和innerValue一起)被限制在outerFunction内。later();
Closure usage scenarios: private variables
在构造器内隐藏变量,使其在外部作用域不可访问,但是可以存在于闭包内。
function Ninja() { var feints = 0; this.getFenits = function() { return feints; } this.feint = function() { feints++; }}var ninja = new Ninja();ninja.feint();assert(ninja.getFenits() === 1, '调用一次,内部变量++');assert(ninja.feints === undefined, '函数外部不可访问')
Prototypes and object-oriented