Dieser Artikel organisiert hauptsächlich einige ähnliche Schlüsselwörter, Methoden und Konzepte in javascript
und teilt sie mit allen, in der Hoffnung, allen zu helfen.
1. Der Unterschied zwischen den Befehlen var, function, let und const
Eine mit var deklarierte Variable hat ihren Gültigkeitsbereich innerhalb der Funktion, in der sich die Anweisung befindet, und Die Variable existiert. Das Hebephänomen
Variablen, die mit let deklariert wurden, haben ihren Gültigkeitsbereich innerhalb des Codeblocks, in dem sich die Anweisung befindet. Es gibt kein Variablenhebephänomen
Const verwenden Was deklariert wird, ist eine Konstante, und der Wert und die Adresse der Konstante auf dem Stapel können im später angezeigten Code nicht geändert werden
Eine mit function deklarierte Funktion hat ihren Gültigkeitsbereich wo sich die Anweisung innerhalb der Funktion befindet und es ein Funktionsförderungsphänomen gibt
-
var
1 2 3 4 5 6 7 8 9 10 11 12 13 | console.log(a)
var a = 123
function f() {
var a = 123
console.log(a)
}
console.log(a)
for ( var i = 0; i < 10; i ++) {}
console.log(i)
|
Nach dem Login kopieren
let
1 2 3 4 5 6 7 | console.log(a)
let a = 123
for (let i = 0; i < 10; i ++) {}
console.log(i)
|
Nach dem Login kopieren
const
1 2 3 4 5 6 7 8 9 10 | const a = 10
a = 20
const a = {
b: 20
}
a.b = 30
console.log(a.b)
|
Nach dem Login kopieren
Funktion
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | fn()
function fn() {
return 123
}
function fn() {
function fn1 () {
return 123456
}
fn1()
}
fn1()
|
Nach dem Login kopieren
Klassische Interviewfragen
1 2 3 4 5 6 7 8 | var a = 1
function fn() {
if (!a) {
var a = 123
}
console.log(a)
}
fn() ?
|
Nach dem Login kopieren
// So drucken Sie 0 - 9 nacheinander aus
1 2 3 4 5 | for ( var i = 0; i < 10; i++) {
setTimeout( function (){
console.log(i)
})
}
|
Nach dem Login kopieren
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | function Foo() {
getName = function (){
console.log( "1" );
};
return this;
}
Foo.getName = function () {
console.log( "2" );
};
Foo.prototype.getName = function (){
console.log( "3" );
};
var getName = function () {
console.log( "4" );
}
function getName(){
console.log( "5" );
}
Foo.getName(); ?
getName(); ?
Foo().getName(); ?
getName(); ?
new Foo.getName(); ?
new Foo().getName(); ?
|
Nach dem Login kopieren
-
Antwort:
Frage 1
1 2 3 4 5 6 7 8 9 10 | var a = 1
function fn() {
var a = nudefined
if (!a) {
var a = 123
}
console.log(a)
}
|
Nach dem Login kopieren
Frage 2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | for ( var i = 0; i < 10; i++) {
print (i)
}
function print (i) {
setTimeout( function (){
console.log(i)
})
}
for ( var i = 0; i < 10; i++) {
( function (i){
setTimeout( function (){
console.log(i)
})
})(i)
}
|
Nach dem Login kopieren
Frage 3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | var getName = undefined
function Foo() {
getName = function (){
console.log( "1" );
};
return this;
}
function getName(){
console.log( "5" );
}
Foo.getName = function () {
console.log( "2" );
};
Foo.prototype.getName = function (){
console.log( "3" );
};
getName = function () {
console.log( "4" );
}
Foo.getName();
getName();
Foo().getName();
getName();
new Foo.getName();
new Foo().getName();
|
Nach dem Login kopieren
Ich erinnere mich, dass ich ein paar klassische Beispiele gesehen habe, aber nach langer Suche konnte ich sie nicht finden das ist alles für den Moment.
2. Der Unterschied zwischen == und ===
Gleiche Punkte:
Beide Operatoren sind zulässige Operanden von Jeder Typ, wenn die Operanden gleich sind, wird true zurückgegeben, andernfalls wird false zurückgegeben
Unterschied:
==: Der Operator ist Wird als Gleichheit bezeichnet und wird verwendet, um zu überprüfen, ob zwei Operanden gleich sind. Die Definition von Gleichheit ist hier sehr locker und ermöglicht die Typkonvertierung sind strikt gleich, es wird keine Typkonvertierung durchgeführt
== Konvertierungsregeln
Erster Blick Doppelte Gleichheit Gibt es NaN vor und nach der Zahl? Wenn NaN vorhanden ist, wird immer false zurückgegeben. - Überprüfen Sie, ob vor und nach dem doppelten Gleichheitszeichen ein Boolescher Wert steht. Wenn es einen Booleschen Wert gibt, wandeln Sie den Booleschen Wert in eine Zahl um. (falsch ist 0, wahr ist 1)
- Überprüfen Sie dann, ob vor und nach dem doppelten Gleichheitszeichen eine Zeichenfolge steht:
Die andere Partei ist ein Objekt, und das Objekt verwendet toString() oder valueOf() zur Konvertierung; - b. Wenn die andere Partei eine Zahl ist, vergleiche direkt;
d. Andernfalls wird false zurückgegeben
Wenn es sich um eine Zahl und die andere Partei um ein Objekt handelt, vergleichen Sie das Objekt mit valueOf() oder toString(), andernfalls wird es zurückgegeben return false
null, undefiniert wird nicht typkonvertiert, aber Sie sind beide gleich
Die folgenden Bilder zeigen die Beziehung zwischen diesen == ===
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | var a = 1
var b = '1'
console.log(a == b)
console.log(a === b)
console.log([1,2,3] == '1,2,3')
console.log([] == true)
console.log(['1'] == 1)
console.log(2 == {valueOf: function (){ return 2}})
console.log(null == 1)
console.log(null == 0)
console.log(undefined == 1)
console.log(undefined == 0)
console.log(null == false)
console.log(undefined == false)
console.log(null == undefined)
console.log(null === undefined)
console.log(NaN == NaN)
console.log(NaN === NaN)
|
Nach dem Login kopieren
==
===
3. toSting und valueOf
Alle Objekte erben diese beiden Konvertierungsmethoden
: Rückgabe eine Zeichenfolge, die dieses Objekt widerspiegelt: Gibt seinen entsprechenden Originalwert zurück
toString
valueOf
toString
- valueOf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | var arr = [1,2,3]
var obj = {
a: 1,
b: 2
}
console.log(arr.toString())
console.log(obj.toString())
Array.prototype.toString = function (){ return 123 }
Object.prototype.toString = function (){ return 456 }
console.log(arr.toString())
console.log(obj.toString())
console.log(( new Date ).toString())
console.log(/\d+/g.toString())
console.log(( new RegExp('asdad', 'ig')).toString())
console.log(true.toString())
console.log(false.toString())
console.log( function (){console.log(1)}.toString())
console.log(Math.random().toString())
|
Nach dem Login kopieren
- toString and valueOf Instanzen
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | var arr = [1,2,3]
var obj = {
a: 1,
b: 2
}
console.log(arr.valueOf())
console.log(obj.valueOf())
Array.prototype.valueOf = function (){ return 123 }
Object.prototype.valueOf = function (){ return 456 }
console.log(arr.valueOf())
console.log(obj.valueOf())
console.log(( new Date ).valueOf())
console.log(/\d+/g.valueOf())
console.log(Math.valueOf())
console.log( function (){console.log(1)}.valueOf())
|
Nach dem Login kopieren
1 2 3 4 5 6 7 8 9 10 | var a = {
toString: function () {
console.log('你调用了a的toString函数')
return 8
}
}
console.log( ++a)
|
Nach dem Login kopieren
- 4. Der Unterschied zwischen ||. und &&
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | var a = {
num: 10,
toString: function () {
console.log('你调用了a的toString函数')
return 8
},
valueOf: function () {
console.log('你调用了a的valueOf函数')
return this.num
}
}
console.log( ++a)
|
Nach dem Login kopieren
Wenn Sie „||“ und „&&“ verwenden, um eine bedingte Beurteilung zu treffen
"||" Solange eine davon wahr ist, ist die Bedingung erfüllt
||. oder) :- 1. Solange „||“ davor wahr ist, gibt das Ergebnis „||“ zurück. Der vorherige Wert
2. Wenn „||“ falsch ist Das Ergebnis ist „||“ und der folgende Wert wird zurückgegeben
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | var a = true,b = false, c = true, d = false
var str = 'none'
if (b || d || a) { str = '现在是 ||' }
console.log(str)
var str = 'none'
if (b || d ) { str = '现在是 ||' }
console.log(str)
var str = 'none'
if (a && c && d) { str = '现在是 &&' }
console.log(str)
var str = 'none'
if (a && c) { str = '现在是 &&' }
console.log(str)
|
Nach dem Login kopieren
&& (und) : - 1. Solange „&&“ " steht nach „&&“ vor „false“, egal ob „true“ oder „false“, das Ergebnis gibt den Wert vor „&&“ zurück
2. Solange „&&“ mit „true“ vorangestellt ist, egal ob „&&“ " folgt true oder false, das Ergebnis gibt den Wert nach "&&" zurück
1 2 3 | var a = false, b = true
console.log(a && b)
console.log(b && a)
|
Nach dem Login kopieren
5. Der Unterschied zwischen call/bind/apply
Offensichtlich sind „Call“ und „Apply“ ähnlicher und „Bind“ unterscheidet sich von den beiden Formen.
Was ist also der Unterschied zwischen „Call“ und „Apply“?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | var name = '小刚'
var person = {
name: '小明',
fn: function () {
console.log(this.name + '撸代码')
}
}
person.fn()
person.fn.call(window)
person.fn.apply(window)
person.fn.bind(window)()
|
Nach dem Login kopieren
Was ist also der Unterschied zwischen bind und call, apply Was?
Im Gegensatz zu call und apply wird bind nicht sofort nach dem Binden ausgeführt. Es wird nur dieser Punkt der Funktion ermittelt und dann die Funktion
zurückgegeben
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | var name = "小红"
var obj = {
name: '小明',
fn: function (){
console.log('我是'+this.name)
}
}
setTimeout(obj.fn, 1000)
setTimeout(obj.fn.bind(obj), 1000)
Function.prototype.bind = function (oThis) {
if (typeof this !== "function" ) {
throw new TypeError( "Function.prototype.bind - what is trying to be bound is not callable" );
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function () {},
fBound = function () {
return fToBind.apply(
this instanceof fNOP && oThis ? this : oThis || window,
aArgs.concat(Array.prototype.slice.call(arguments))
);
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
};
|
Nach dem Login kopieren
6. callback 、 promise 、 async/await
这三个东西牵涉到的可能就是我们最常见到的 “同步”、“异步”、“任务队列”、“事件循环” 这几个概念了
例:
1 2 3 4 5 6 7 8 | var data;
$.ajax({
...
success: function (data) {
data = data
}
})
console.log(data)
|
Nach dem Login kopieren
当我们从服务器获取到数据的时候,为什么打印出来的是undefined ?
解决这个问题之前我们先来了解javascript的运行环境
JavaScript是单线程语言,JS中所有的任务可以分为两种:同步任务和异步任务。
同步任务:
意思是我必须做完第一件事,才能做第二件事,按照顺序一件一件往下执行(在主线程上)
异步任务:
假如我第一件事需要花费 10s, 但是我第二件事急着要做, 于是我们就把第一件事告诉主线程,然后主线程暂停先放到某个地方, 等把第二件事完成之后,再去那个地方执行第一件事,第一件事也就可以理解为异步任务
任务队列(task queue):
任务队列是干嘛的呢; 上面我们说了异步任务的情况, 我们把第一件放到某个地方, 那某个地方是什么地方呢,就是 “任务队列” 这个东西。里面乘放的是所有异步任务。
Event Loop(事件循环)
当主线程上面所有同步任务执行完之后,主线程就会向任务队列中读取异步任务(队列方法:先进先出)
而且是一直重复向任务队列中,即使没有任务。它也会一直去轮询。
只不过在任务列表里面没有任务的时候, 主线程只需要稍微过一遍就行, 一旦遇到任务队列里面有任务的时候,就会去执行它
也就是说在我们打开网页的时候,JS引擎会一直执行事件循环,直到网页关闭
如图所示

由此,上面为什么会产生 undefined的原因了, 因为ajax 是异步任务,而我们console.log(data)是同步任务,所以先执行的同步任务,才会去执行 ajax
说了这么多,我们来看下 为什么我们很需要 从 callback
=> promise
=> async/await
因为很多时候我们需要把一个异步任务的返回值,传递给下一个函数,而且有时候是连续的n个
callback
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | function fn(callback) {
setTimeout( function (){
callback && callback()
}, 1000)
}
fn( function (){
console.log(1)
})
function fn(a){
function fn1(a1){
function fn2(a2){
function fn3(a3){
console.log(a3)
....
}
}
}
}
|
Nach dem Login kopieren
Promise
什么是promise?
Promise是异步编程的一种解决方案,同时也是ES6的内置对象,它有三种状态:
Promise方法
基本用法
1 2 3 4 5 6 7 8 | let promise = new Promise( (resolve, reject) => {
setTimeout( function (){
resolve(1)
}, 1000)
})
promise.then( res => {
console.log(res)
})
|
Nach dem Login kopieren
我们把上面的回调地狱转换下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | const fn = a => {
return Promise.resolve(a)
}
const fn1 = a => {
return Promise.resolve(a)
}
const fn2 = a => {
return new Promise( (resolve, reject) => {
setTimeout( function (){
resolve(a)
},1000)
})
}
const fn3 = a => {
return new Promise( (resolve, reject) => {
setTimeout( function (){
resolve(a)
},1000)
})
}
fn(123)
.then(fn1)
.then(fn2)
.then(fn3)
.then( res => {
console.log(res)
})
|
Nach dem Login kopieren
这样就简单明了多了, 我们就不需要一层一层嵌套callback了,可以通过链式调用来解决callback的问题
然而,仅仅这样还是觉得不够好
因为这种面条式调用还是让人很不爽,而且 then 方法里面虽然是按先后顺序来的,但是其本身还是异步的
看下面这段代码
1 2 3 4 5 6 7 8 9 10 | const promise = new Promise( (resolve, reject) => {
setTimeout( function (){
resolve(222)
}, 1000)
})
console.log(111)
promise.then( res => {
console.log(res)
})
console.log(333)
|
Nach dem Login kopieren
打印结果依然还是 111 => 333 => 222, 并不是我们想象的 111 => 222 => 333
依然不适合单线程的思维模式。所以下一个解决方案 又出现了
Promise.prototype.then() 接收两个函数,一个是处理成功后的函数,一个是处理错误结果的函数。可以进行链式调用
Promise.prototype.catch() 捕获异步操作时出现的异常, 一般我们用来代替.then方法的第二个参数
Promise.resolve() 接受一个参数值,可以是普通的值, 会返回到对应的Promise的then方法上
Promise.reject() 接受一个参数值,可以是普通的值, 会返回到对应的Promise的catch方法上或着then方法的第二个参数上
Promise.all() 接收一个参数,它必须是可以迭代的,比如数组。通常用来处理一些并发的异步操作。成功调用后返回一个数组,数组的值是有序的,即按照传入参数的数组的值操作后返回的结果
Promise.race() 接收一个可以迭代的参数,比如数组。但是只要其中有一个执行了,就算执行完了,不管是成功还是失败。
pending: 进行中
resolved: 已完成
rejected:已失败
async/await
这是ES7的语法,当然,在现在这种工程化的时代,基本babel编译之后也都是能在项目中引用的
7. 柯里化 与 反柯里化
柯里化
函数柯里化就是对高阶函数的降阶处理。
柯里化简单的说,就是把 n 个参数的函数,变成只接受一个参数的 n 个函数
function(arg1,arg2)
变成function(arg1)(arg2)
function(arg1,arg2,arg3)
变成function(arg1)(arg2)(arg3)
function(arg1,arg2,arg3,arg4)
变成function(arg1)(arg2)(arg3)(arg4)
柯里化有什么作用
例:
1 2 3 4 5 | function add (a, b, c) {
return a + b + c
}
add(1,2,3)
|
Nach dem Login kopieren
如果我只改变 c 的值,在求和
add(1,2,4)
是不是得多出重新计算 a + b 的部分
我们是不是可以提前返回a+b的值, 然后只传入 c 的值进行计算就行了
修改一下方法
1 2 3 4 5 6 7 8 | function add (a, b) {
return function (c) {
return a + b + c
}
}
var sum = add(1, 2)
sum(3)
sum(4)
|
Nach dem Login kopieren
在此基础上我们在做下修改
1 2 3 4 5 6 7 | function add (a) {
return function (b) {
return function (c) {
return a + b + c
}
}
}
|
Nach dem Login kopieren
这样我们是不是可以随时复用某个参数,并且控制在某个阶段提前返回
还有一个经典的例子
1 2 3 4 5 6 7 8 9 10 11 | var addEvent = function (el, type, fn, capture) {
if (window.addEventListener) {
el.addEventListener(type, function (e) {
fn.call(el, e);
}, capture);
} else if (window.attachEvent) {
el.attachEvent( "on" + type, function (e) {
fn.call(el, e);
});
}
};
|
Nach dem Login kopieren
我们每次调用事件时,都需要判断兼容问题, 但我们运用柯里化的方式就只要判断一次就行了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | var addEvent = ( function (){
if (window.addEventListener) {
return function (el, sType, fn, capture) {
el.addEventListener(sType, function (e) {
fn.call(el, e);
}, (capture));
};
} else if (window.attachEvent) {
return function (el, sType, fn, capture) {
el.attachEvent( "on" + sType, function (e) {
fn.call(el, e);
});
};
}
})();
|
Nach dem Login kopieren
还有一个作用就是延迟计算
小明每天都会花一部分钱吃饭
小明想知道它5天之后总共会花费多少钱
1 2 3 4 5 6 7 8 9 | var total = 0
var fn = function (num) {
total += num
}
fn(50)
fn(70)
fn(60)
fn(100)
fn(80)
|
Nach dem Login kopieren
这样我们便能算出它总共花了都少钱
但是小明又突然想知道 如果他每天花费的的钱翻一倍 会产生多少钱
于是我们是不是得改下 上面的 函数
1 2 3 4 5 6 7 8 | var fn = function (num) {
total += num*2
}
fn(50)
fn(70)
fn(60)
fn(100)
fn(80)
|
Nach dem Login kopieren
那我们是不是有什么办法,先把这些数 存起来,到最后在进行计算
我们接着来封装
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | var curry = function (fn) {
var args = []
return function () {
if (arguments.length === 0) {
return fn.apply(null, args)
} else {
args = args.concat([].slice.call(arguments))
return curry.call(null, fn, args)
}
}
}
var curryFn = function () {
var args = [].slice.call(arguments),
total = 0
for ( var i = 0; i < args.length; i++) {
total += args[i]
}
return total
}
var fn = curry(curryFn)
fn(50)
fn(70)
fn(60)
fn(100)
fn(80)
fn()
|
Nach dem Login kopieren
这样我们只有最后的时候才进行计算。
而且只需要修改 curryFn 里面的计算方法就行
我们整理下上面的方法封装完整的柯里化函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | var curry = function (fn, length) {
length = length || fn.length;
var sub_curry = function (f) {
var args = [].slice.call(arguments, 1);
return function () {
return f.apply(null, args.concat([].slice.call(arguments)))
}
}
return function () {
var args = [].slice.call(arguments);
if (length > args.length) {
var newArgs = [fn].concat(args);
return curry(sub_curry.apply(null,newArgs), length - args.length)
} else {
fn.apply(null,arguments)
}
}
}
|
Nach dem Login kopieren
1 2 3 4 5 6 7 8 9 10 11 | var fn = curry( function (a,b,c){
console.log(a, b, c)
})
fn('a')('b')('c')
fn1 = curry( function (){
console.log(arguments)
}, 3)
fn1('a')('b')('c')
|
Nach dem Login kopieren
参数复用;
提前返回;
延迟计算/运行
反柯里化
反柯里化的作用在与扩大函数的适用性,使本来作为特定对象所拥有的功能的函数可以被任意对象所用.
被任意对象使用? 是不是想到了用call, apply 设置this指向
通过 call/apply 被任意对象所用
1 2 3 4 5 6 7 8 9 | var obj = {
a: 1,
fn: function (b) {
return this.a + b
}
}
obj.fn(2)
var obj1 = {a:4}
obj.fn.call(obj1, 2)
|
Nach dem Login kopieren
反柯里化版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | var uncurrying= function (fn) {
return function () {
var context=[].shift.call(arguments);
return fn.apply(context,arguments);
}
}
var f = function (b) {
return this.a + b
}
var uncurry = uncurrying(f)
var obj = {a:1},
obj1 = {a:4}
uncurry(obj, 2)
uncurry(obj1, 2)
|
Nach dem Login kopieren
相信大家已经看出区别了,这丫的就相当于一个外部的call方法
总结
上面很多只是自己的部分理解,不一定准确。如果有不同理解,谢谢指出。
相关推荐:
最全JavaScript知识点总结
一些容易犯错的JavaScript知识点整理
JavaScript知识点系统总结
Das obige ist der detaillierte Inhalt vonZusammenfassung der JavaScript-Kenntnisse. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!