cari
Rumahhujung hadapan webtutorial jsSemua yang anda ingin ketahui tentang petua JavaScript scopes_javascript

Terdapat satu siri konsep skop dalam Javascript. Pembangun yang baru menggunakan JS tidak dapat memahami konsep ini, malah sesetengah pembangun berpengalaman mungkin tidak dapat memahaminya. Tujuan utama artikel ini adalah untuk membantu memahami beberapa konsep dalam JavaScript seperti: skop, penutupan, ini, ruang nama, skop fungsi, skop global, skop leksikal dan skop awam/peribadi Saya harap artikel ini dapat menjawab soalan berikut:

  • Apakah skop?
  • Apakah skop global dan tempatan?
  • Apakah perbezaan antara ruang nama dan skop?
  • Apakah kata kunci ini dan bagaimana skop mempengaruhinya?
  • Apakah skop fungsi dan skop leksikal?
  • Apakah itu penutupan?
  • Apakah skop awam dan persendirian?
  • Bagaimana untuk memahami dan mencipta kandungan di atas?

1. Apakah Skop?
Dalam JavaScript, skop biasanya merujuk kepada konteks kod. Keupayaan untuk menentukan skop global atau tempatan. Memahami skop JavaScript adalah prasyarat untuk menulis kod yang mantap dan menjadi pembangun yang baik. Anda perlu tahu tempat untuk mendapatkan pembolehubah dan fungsi, tempat untuk menukar skop konteks kod anda dan cara menulis kod yang pantas dan boleh dibaca serta mudah untuk nyahpepijat.

Membayangkan skop adalah sangat mudah, adakah kita dalam skop A atau skop B?

2. Apakah Skop Global?
Sebelum menulis baris pertama kod JavaScript, kami berada dalam skop global. Pada ketika ini kita mentakrifkan pembolehubah, biasanya pembolehubah global.

// global scopevar name = 'Todd';

Skop global ialah rakan dan mimpi ngeri anda. Belajar mengawal skop adalah mudah dan sebaik sahaja anda mempelajari cara menggunakan pembolehubah global, anda tidak akan menghadapi masalah (biasanya konflik ruang nama). Saya sering mendengar orang berkata "skop global adalah buruk", tetapi tidak pernah memikirkan sebabnya dengan serius. Bukan skop global buruk, ia adalah isu penggunaan. Semasa mencipta Modul/API silang skop, kita mesti menggunakannya tanpa menyebabkan masalah.

jQuery('.myClass');

...Kami mendapat jQuery dalam skop global, kami boleh memanggil rujukan ini ruang nama. Ruang nama biasanya merujuk kepada skop di mana perkataan boleh ditukar, tetapi yang biasanya merujuk kepada skop peringkat lebih tinggi. Dalam contoh di atas, jQuery berada dalam skop global, juga dikenali sebagai ruang nama. jQuery ditakrifkan dalam skop global sebagai ruang nama, yang berfungsi sebagai ruang arahan perpustakaan jQuery Semua kandungan dalam perpustakaan menjadi keturunan ruang nama.

2. Apakah Skop Tempatan?
Skop tempatan biasanya datang selepas skop global. Secara umumnya, terdapat skop global dan setiap fungsi mentakrifkan skop tempatannya sendiri. Mana-mana fungsi yang ditakrifkan di dalam fungsi lain mempunyai skop setempat yang dikaitkan dengan fungsi luar.
Jika anda mentakrifkan fungsi dan mencipta pembolehubah di dalamnya, pembolehubah tersebut ialah pembolehubah tempatan. Contohnya:

// Scope A: Global scope out here
var myFunction = function () {
// Scope B: Local scope in here};

Sebarang pembolehubah tempatan tidak kelihatan kepada pembolehubah global. Kecuali jika terdedah kepada dunia luar. Jika fungsi dan pembolehubah ditakrifkan dalam skop baharu, ia adalah pembolehubah dalam skop baharu semasa dan tidak boleh diakses di luar skop semasa. Berikut ialah contoh mudah:

var myFunction = function () {
var name = 'Todd';
console.log(name); // Todd};
// Uncaught ReferenceError: name is not defined
console.log(name);

Nama pembolehubah ialah pembolehubah setempat dan tidak terdedah kepada skop induk, jadi ia tidak ditakrifkan.

3. Skop fungsi
Skop fungsi dalam JavaScript ialah skop minimum. Baik gelung for mahupun while mahupun if dan suis boleh membina skop. Peraturannya ialah, fungsi baru mempunyai domain baru. Contoh mudah untuk mencipta domain adalah seperti berikut:

// Scope A
var myFunction = function () {
// Scope B
var myOtherFunction = function () {// Scope C};};

Sangat mudah untuk mencipta domain baharu dan pembolehubah, fungsi dan objek setempat.

4. Skop Leksikal
Apabila fungsi bersarang dalam fungsi lain, dan fungsi dalam boleh mengakses skop fungsi luar, kaedah ini dipanggil Skop Leksikal (Lexical Socpe) atau penutupan, juga dikenali sebagai skop statik. Contoh yang paling menggambarkan masalah ini adalah seperti berikut:

// Scope A
var myFunction = function () {
// Scope B
var name = 'Todd'; // defined in Scope B
var myOtherFunction = function () {
// Scope C: `name` is accessible here!};
};

MyOtherFunction hanya ditakrifkan di sini dan tidak dipanggil. Susunan panggilan ini juga mempengaruhi output pembolehubah. Di sini saya mentakrifkan dan memanggil fungsi dalam konsol lain.

var myFunction = function () {
var name = 'Todd';
var myOtherFunction = function () {
console.log('My name is ' + name);
};
console.log(name);
myOtherFunction(); // call function
};
// Will then log out:// `Todd`
// `My name is Todd`

Skop leksikal lebih mudah digunakan Sebarang pembolehubah, objek dan fungsi yang ditakrifkan dalam skop induk boleh digunakan dalam rantai skop domainnya. Contohnya:

var name = 'Todd';
var scope1 = function () {
// name is available here
var scope2 = function () {// name is available here too
var scope3 = function () {// name is also available here!};
};
};

唯一需要注意的事情是词汇域不后项起作用,下面的方式词汇域是不起作用的:

// name = undefined
var scope1 = function () {
// name = undefined
var scope2 = function () {// name = undefined
var scope3 = function () {var name = 'Todd'; // locally scoped};
};
};

能返回对name的引用,但是永远也无法返回变量本身。

5、作用域链
函数的作用域由作用域链构成。我们知道,每个函数可以定义嵌套的作用域,任何内嵌函数都有一个局部作用域连接外部函数。这种嵌套关系我们可以称为链。域一般由代码中的位置决定。当解释(resolving)一个变量,通常从作用域链的最里层开始,向外搜索,直到发现要寻找的变量、对象或者函数。

6、闭包(Closures)
闭包和词法域( Lexical Scope)很像。返回函数引用,这种实际应用,是一个可以用来解释闭包工作原理的好例子。在我们的域内部,我们可以返回对象,能够被父域使用。

var sayHello = function (name) {
var text = 'Hello, ' + name;
return function () {
console.log(text);};
};

这里我们使用的闭包,使得我们的sayHello内部域无法被公共域访问到。单独调用函数并不作任何操作,因为其单纯的返回一个函数。

sayHello('Todd'); // nothing happens, no errors, just silence...

函数返回一个函数,也就意味着需要先赋值再调用:

var helloTodd = sayHello('Todd');
helloTodd(); // will call the closure and log 'Hello, Todd'

好吧,欺骗大家感情了。在实际情况中可能会遇到如下调用闭包的函数,这样也是行的通的。

sayHello2('Bob')(); // calls the returned function without assignment

Angular js 在$compile方法中使用上面的技术,可以将当前引用域传入到闭包中

$compile(template)(scope);

意味着我们能够猜出他们的代码(简化)应该如下:

var $compile = function (template) {
// some magic stuff here// scope is out of scope, though...
return function (scope) {// access to `template` and `scope` to do magic with too};
};

闭包并不一定需要返回函数。单纯在中间词汇域量的范围外简单访问变量就创造了一个闭包。

7、作用域和this关键字
根据函数被触发的方式不一样,每个作用域可以绑定一个不同的this值。我们经常使用this,但是我们并不是都了解其具体指代什么。 this默认是执行最外层的全局对象,windows对象。我们能够很容易的列举出不同触发函数绑定this的值也不同:

var myFunction = function () {
console.log(this); // this = global, [object Window]};
myFunction();
var myObject = {};
myObject.myMethod = function () {
console.log(this); // this = Object { myObject }};
var nav = document.querySelector('.nav'); // <nav class="nav">
var toggleNav = function () {
console.log(this); // this = <nav> element};
nav.addEventListener('click', toggleNav, false);

在处理this值的时候,也会遇到问题。下面的例子中,即使在相同的函数内部,作用域和this值也会不同。

var nav = document.querySelector('.nav');
 // <nav class="nav">
var toggleNav = function () {
console.log(this); // <nav> element
setTimeout(function () {
console.log(this); // [object Window]}, 1000);
};
nav.addEventListener('click', toggleNav, false);

发生了什么?我们创建了一个新的作用域且没有在event handler中触发,所以其得到预期的windows对象。如果想this值不受新创建的作用域的影响,我们能够采取一些做法。以前可能也你也见过,我们使用that创建一个对this的缓存引用并词汇绑定:

var nav = document.querySelector('.nav'); // <nav class="nav">
var toggleNav = function () {
var that = this;
console.log(that); // <nav> element
setTimeout(function () {
console.log(that); // <nav> element}, 1000);
};
nav.addEventListener('click', toggleNav, false);

这是使用this的一个小技巧,能够解决新创建的作用域问题。

8、使用.call(), .apply() 和.bind()改变作用域
有时候,需要根据实际的需求来变化代码的作用域。一个简单的例子,如在循环中如何改变作用域:

var links = document.querySelectorAll('nav li');
for (var i = 0; i < links.length; i++) {
console.log(this); // [object Window]}

这里的this并没有指向我们的元素,因为我们没有触发或者改变作用域。我们来看看如何改变作用域(看起来我们是改变作用域,其实我们是改变调用函数执行的上下文)。

9、.call() and .apply()
.call()和.apply()方法非常友好,其允许给一个函数传作用域来绑定正确的this值。对上面的例子我们通过如下改变,可以使this为当前数组里的每个元素。

var links = document.querySelectorAll('nav li');
for (var i = 0; i < links.length; i++) {
(function () {
console.log(this);
}).call(links[i]);}

能够看到刚将数组循环的当前元素通过links[i]传递进去,这改变了函数的作用域,因此this的值变为当前循环的元素。这个时候,如果需要我们可以使用this。我们既可以使用.call()又可以使用.apply()来改变域。但是这两者使用还是有区别的,其中.call(scope, arg1, arg2, arg3)输入单个参数,而.apply(scope, [arg1, arg2])输入数组作为参数。

非常重要,需要注意的事情是.call() or .apply()实际已经已经取代了如下调用函数的方式调用了函数。

myFunction(); // invoke myFunction
可以使用.call()来链式调用:

myFunction.call(scope); // invoke myFunction using .call()
10、.bind()
和上面不一样的是,.bind()并不触发函数,它仅仅是在函数触发前绑定值。非常遗憾的是其只在 ECMASCript 5中才引入。我们都知道,不能像下面一样传递参数给函数引用:

// works
nav.addEventListener('click', toggleNav, false);
// will invoke the function immediately
nav.addEventListener('click', toggleNav(arg1, arg2), false);

通过在内部创建一个新的函数,我们能够修复这个问题(译注:函数被立即执行):

nav.addEventListener('click', function () {
toggleNav(arg1, arg2);}, false);

但是这样的话,我们再次创建了一个没用的函数,如果这是在循环中绑定事件监听,会影响代码性能。这个时候.bind()就派上用场了,在不需要调用的时候就可以传递参数。

nav.addEventListener('click', toggleNav.bind(scope, arg1, arg2), false);

函数并没被触发,scope可以被改变,且参数在等着传递。

11、私有和公开作用域
在许多的编程语言中,存在public和private的作用域,但是在javascript中并不存在。但是在JavaScript中通过闭包来模拟public和private的作用域。

使用JavaScript的设计模式,如Module模式为例。一个创建private的简单方式将函数内嵌到另一个函数中。如我们上面掌握的,函数决定scope,通过scope排除全局的scope:

(function () {// private scope inside here})();

然后在我们的应用中添加一些函数:

(function () {
var myFunction = function () 
{// do some stuff here};
})();

这时当我们调用函数的时候,会超出范围。

(function () {var myFunction = function () {
// do some stuff here};
})();
myFunction(); // Uncaught ReferenceError: myFunction is not defined

成功的创建了一个私有作用域。那么怎么让函公有呢?有一个非常好的模式(模块模式)允许通过私有和公共作用域以及一个object对象来正确的设定函数作用域。暂且将全局命名空间称为Module,里面包含了所有与模块相关的代码:

// define module
var Module = (function () {
return {myMethod: function () {
console.log('myMethod has been called.');}};
})();
// call module + methods
Module.myMethod();

这儿的return 语句返回了公共的方法,只有通过命名空间才能够被访问到。这就意味着,我们使用Module 作为我们的命名空间,其能够包含我们需要的所有方法。我们可以根据实际的需求来扩展我们的模块。

// define module
var Module = (function () {
return {myMethod: function () {},
someOtherMethod: function () {}};})();
// call module + methods
Module.myMethod();
Module.someOtherMethod();

那私有方法怎么办呢?许多的开发者采取错误的方式,其将所有的函数都至于全局作用域中,这导致了对全局命名空间污染。 通过函数我们能避免在全局域中编写代码,通过API调用,保证可以全局获取。下面的示例中,通过创建不返回函数的形式创建私有域。

var Module = (function () {
var privateMethod = function () {};
return {
publicMethod: function () {}};})();

这就意味着publicMethod 能够被调用,而privateMethod 由于私有作用域不能被调用。这些私有作用域函数类似于: helpers, addClass, removeClass, Ajax/XHR calls, Arrays, Objects等。

下面是一个有趣事,相同作用域中的对象只能访问相同的作用域,即使有函数被返回之后。这就意味我们的public方法能够访问我们的private方法,这些私有方法依然可以起作用,但是不能够在全局左右域中访问。

var Module = (function () {
var privateMethod = function () {};
return {publicMethod: function () {
// has access to `privateMethod`, we can call it:
// privateMethod();}};})();

这提供了非常强大交互性和安全性机制。Javascript 的一个非常重要的部分是安全性,这也是为什么我们不能将所有的函数放在全局变量中,这样做易于被攻击。这里有个通过public和private返回Object对象的例子:

var Module = (function () {
var myModule = {};
var privateMethod = function () {};
myModule.publicMethod = function () {};
myModule.anotherPublicMethod = function () {};
return myModule; // returns the Object with public methods})();
// usage
Module.publicMethod();

通常私有方法的命名开头使用下划线,从视觉上将其与公有方法区别开。

var Module = (function () {
var _privateMethod = function () {};
var publicMethod = function () {};})();

当返回匿名对象的时候,通过简单的函数引用赋值,Module可以按照对象的方式来用。

var Module = (function () 
{var _privateMethod = function () {};
var publicMethod = function () {};
return {
publicMethod: publicMethod,anotherPublicMethod: anotherPublicMethod}
})();

以上就是关于JavaScript作用域的全部内容,希望对大家的学习有所帮助。

Kenyataan
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
es6数组怎么去掉重复并且重新排序es6数组怎么去掉重复并且重新排序May 05, 2022 pm 07:08 PM

去掉重复并排序的方法:1、使用“Array.from(new Set(arr))”或者“[…new Set(arr)]”语句,去掉数组中的重复元素,返回去重后的新数组;2、利用sort()对去重数组进行排序,语法“去重数组.sort()”。

JavaScript的Symbol类型、隐藏属性及全局注册表详解JavaScript的Symbol类型、隐藏属性及全局注册表详解Jun 02, 2022 am 11:50 AM

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于Symbol类型、隐藏属性及全局注册表的相关问题,包括了Symbol类型的描述、Symbol不会隐式转字符串等问题,下面一起来看一下,希望对大家有帮助。

原来利用纯CSS也能实现文字轮播与图片轮播!原来利用纯CSS也能实现文字轮播与图片轮播!Jun 10, 2022 pm 01:00 PM

怎么制作文字轮播与图片轮播?大家第一想到的是不是利用js,其实利用纯CSS也能实现文字轮播与图片轮播,下面来看看实现方法,希望对大家有所帮助!

JavaScript对象的构造函数和new操作符(实例详解)JavaScript对象的构造函数和new操作符(实例详解)May 10, 2022 pm 06:16 PM

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于对象的构造函数和new操作符,构造函数是所有对象的成员方法中,最早被调用的那个,下面一起来看一下吧,希望对大家有帮助。

JavaScript面向对象详细解析之属性描述符JavaScript面向对象详细解析之属性描述符May 27, 2022 pm 05:29 PM

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于面向对象的相关问题,包括了属性描述符、数据描述符、存取描述符等等内容,下面一起来看一下,希望对大家有帮助。

javascript怎么移除元素点击事件javascript怎么移除元素点击事件Apr 11, 2022 pm 04:51 PM

方法:1、利用“点击元素对象.unbind("click");”方法,该方法可以移除被选元素的事件处理程序;2、利用“点击元素对象.off("click");”方法,该方法可以移除通过on()方法添加的事件处理程序。

foreach是es6里的吗foreach是es6里的吗May 05, 2022 pm 05:59 PM

foreach不是es6的方法。foreach是es3中一个遍历数组的方法,可以调用数组的每个元素,并将元素传给回调函数进行处理,语法“array.forEach(function(当前元素,索引,数组){...})”;该方法不处理空数组。

整理总结JavaScript常见的BOM操作整理总结JavaScript常见的BOM操作Jun 01, 2022 am 11:43 AM

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于BOM操作的相关问题,包括了window对象的常见事件、JavaScript执行机制等等相关内容,下面一起来看一下,希望对大家有帮助。

See all articles

Alat AI Hot

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

AI Hentai Generator

AI Hentai Generator

Menjana ai hentai secara percuma.

Artikel Panas

R.E.P.O. Kristal tenaga dijelaskan dan apa yang mereka lakukan (kristal kuning)
3 minggu yang laluBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Tetapan grafik terbaik
3 minggu yang laluBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Cara Memperbaiki Audio Jika anda tidak dapat mendengar sesiapa
3 minggu yang laluBy尊渡假赌尊渡假赌尊渡假赌

Alat panas

Pelayar Peperiksaan Selamat

Pelayar Peperiksaan Selamat

Pelayar Peperiksaan Selamat ialah persekitaran pelayar selamat untuk mengambil peperiksaan dalam talian dengan selamat. Perisian ini menukar mana-mana komputer menjadi stesen kerja yang selamat. Ia mengawal akses kepada mana-mana utiliti dan menghalang pelajar daripada menggunakan sumber yang tidak dibenarkan.

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

Persekitaran pembangunan bersepadu PHP yang berkuasa

MinGW - GNU Minimalis untuk Windows

MinGW - GNU Minimalis untuk Windows

Projek ini dalam proses untuk dipindahkan ke osdn.net/projects/mingw, anda boleh terus mengikuti kami di sana. MinGW: Port Windows asli bagi GNU Compiler Collection (GCC), perpustakaan import yang boleh diedarkan secara bebas dan fail pengepala untuk membina aplikasi Windows asli termasuk sambungan kepada masa jalan MSVC untuk menyokong fungsi C99. Semua perisian MinGW boleh dijalankan pada platform Windows 64-bit.

SublimeText3 versi Cina

SublimeText3 versi Cina

Versi Cina, sangat mudah digunakan

EditPlus versi Cina retak

EditPlus versi Cina retak

Saiz kecil, penyerlahan sintaks, tidak menyokong fungsi gesaan kod