JS知识点+试题(二)
作者:互联网
作用域
循环陷阱
什么是循环陷阱?
var a = []; for (var i = 0; i < 10; i++) { a[i] = function () { console.log(i); }; } a[6](); // 10
- 由于匿名函数中使用的变量 i 在作用域外声明形成闭包
- i 属于全局作用域
- 所以循环中创建的匿名函数都指向同一个变量
循环陷阱就是看似每个新创建的函数都需要一个单独的变量,但没有实现
解决:
A.IIFE即时执行函数解决var a = []; for (var i = 0; i < 10; i++) { (function(n) { a[i] = function () { console.log(n); }; })(i) } a[6](); // 6
B.ES6 使用let ——块级作用域
var a = []; for (let i = 0; i < 10; i++) { a[i] = function () { console.log(i); }; } a[6](); // 6
问:为什么块级作用域存在并使用?
答:在Javascript提出块级作用域,主要为了解决一个重要的设计缺陷 。> 变量提升特性导致的大量与直觉不符的代码 SO,变量提升是什么?
(function() { console.log(v) var v = 123 })()//undefined // 变量提升后 (function() { var v console.log(v) v = 123 })()JS在变量声明提升的时候会将 var 声明的变量以及 用关键字函数声明的函数都会提升到当前作用域的顶端 。赋值语句在原地等待赋值。 优点是降低程序的编写难度,无明确顺序要求。
var tmp = new Date(); function f() { console.log(tmp); if (false) { var tmp = 'hello world'; } } f(); // undefined
问:let是否会造成变量提升
var a = 8; (function() { // let a 此时暂时性死区开始 console.log(a); // Uncaught ReferenceError: x is not defined //暂时性死区结束 let a = 1 }())
//报错
导致现象:
暂时性死区 (Temporal Dead Zone)引用MDN上的定义
> let bindings are created at the top of the (block) scope containing the declaration, commonly referred to as “hoisting”. Unlike variables declared with var, which will start with the value undefined, let variables are not initialized until their definition is evaluated. Accessing the variable before the initialization results in a ReferenceError. The variable is in a “temporal dead zone” from the start of the block until the initialization is processed.
大概意思便是let同样存在变量提示(hoisting),只是形式与var不同,var定义的变量将会被赋予undefined的初始值,而let在被显式赋值之前不会被赋予初始值,并且在赋值之前读写变量都会导致 ReferenceError 的报错。从代码块(block)起始到变量求值(包括赋值)以前的这块区域,称为该变量的暂时性死区。 BUT,红宝书没有这样的叙述 答:不做判断型回答- 陈述客观事实 - 代码现象 - MDN与红宝书记述
this指向
function say() { console.log("我的家乡", this.name); } var bj = { name:'北京', say } window.name = "中国"; say(); // 我的家乡 中国 bj.say();// 我的家乡 北京
1.
普通函数
如果一个函数不属于任何一个对象,上下文就是全局对象。在浏览器中就是window,如果是node运行时中就是global 2. 对象属性
接着说一下在对象中的this指向。this指向在对象中指向对象实例。其实归属某一个对象才是上下文环境使用最多的情况。同样一个方法可以根据对象实例中数据成员的不同产生不同的变化。 3. 构造函数与Class
类是对象实例,可以认为是实例的模板。
比如一个国家模板,实例一个国家比如中国。
当然国家模板中的say方法指向的创建的对象实例china
function say() { console.log("我的家乡:", this.name); } function Country(name) { this.name = name } Country.prototype.say = say const china = new Country('中国') china.say() //我的家乡: 中国
ES6
class关键字同理,构造函数constructor等同于上文中的Country构造函数class Country { constructor(name) { this.name = name } say() { console.log("我的家乡:", this.name); } } const china = new Country('中国') china.say()
4. call、apply、bind方法中
function say() { console.log('我的家乡:' + this.name) } window.name = '中国' say() say.apply({name : '北京'}) say.call({name : '朝阳'})
var mySay = say.bind({name: '曹县'}) mySay()
严格模式下this
//函数外指向window "use strict" console.log(this) // window function foo() { console.log(this) // undefined } foo()
箭头函数
在箭头函数中,this总是指向词法作用域,也就是外层调用者。而不是方法所在对象。
function say() { console.log("我的家乡在"+this.name); } var bj = { name: "北京", say: () => say(), chaoyang: { name: "朝阳", say : () => say(), // 修改为箭头函数 }, }; name = '中国' bj.say(); // 我的家乡在中国 bj.chaoyang.say(); // 我的家乡在中国
标签:function,知识点,console,试题,JS,say,log,var,name 来源: https://www.cnblogs.com/clematis/p/16059662.html