工作中积累的问题、知识点总结100题(0-20)
1.给定一个只包括'(',')','{','}','[',']'的字符串,判断字符串是否有效
满足以下要求:
左括号必须用相同类型的右括号闭合
左括号必须以正确的顺序闭合
// 方法1 fun(str) { let len = str.length; if (len % 2 != 0) return false; let arr = []; for (let i = 0; i < len; i++) { let ll = arr[arr.length - 1]; switch (str[i]) { case '(': arr.push(str[i]) break; case '[': arr.push(str[i]) break; case '{': arr.push(str[i]) break; case ')': if (ll == '(') arr.pop(); else return false break; case '}': if (ll == '{') arr.pop(); else return false break; case ']': if (ll == '[') arr.pop(); else return false break; } } return arr.length == 0 }
// 方法2,其实和方法1是一样的,就是写法不一样 fun(str) { let len = str.length; if (len % 2 != 0) return false; let arr = []; for (let i = 0; i < len; i++) { if (str[i] == '(' || str[i] == '[' || str[i] == '{') { arr.push(str[i]) } else { if (str[i] == ')' && arr.pop() != '(') { return false } if (str[i] == '}' && arr.pop() != '{') { return false } if (str[i] == ']' && arr.pop() != '[') { return false } } } return arr.length == 0 }
2.让蓝色div在红色div中垂直居中
/*方法1--通过 flex 布局实现*/ .parent { width: 200px; height: 200px; background-color: red; display: flex; justify-content: center; align-items: center; .children { width: 50px; height: 50px; background-color: #409EFF; } }
/*方法2--通过 position 定位实现,局限性,必须要知道子元素的高宽*/ .parent { width: 200px; height: 200px; background-color: red; position: relative; .children { width: 50px; height: 50px; background-color: #409EFF; position: absolute; top: 50%; left: 50%; margin-top: -25px; margin-left: -25px; } }
/*方法三、通过 transform 实现*/ .parent { width: 200px; height: 200px; background-color: red; position: relative; .children { width: 50px; height: 50px; background-color: #409EFF; position: absolute; left: 50%; top: 50%; transform: translate(-50%,-50%); } }
3.字符串反转
fun(str){ return str.split('').reverse().join('') }
// 2 fun(str) { let ar = str.split(''); let newStr = []; ar.map((i, index) => { newStr.push(ar[ar.length - index - 1]) }) return newStr.join('') }
4.css画一个三角形
.children { width: 0px; height: 0px;
border: 10px solid transparent; border-left: 20px solid blue;
/* border-top: 10px solid transparent; border-bottom: 10px solid transparent; border-left: 10px solid blue;*/ }
5.ECMA中所有函数的参数都是按值传递的
值传递:把把一个值类型(也叫基本类型)传递给另一个变量时,其实是分配了一块新的存储空间,因此就本题来说,在内部改变这个值时,其实在函数外部对这个值没有影响。
var bb = 1; function aa(bb) { bb = 2; alert(bb); }; aa(bb); alert(bb);
函数体内,bb并没有使用var来定义,按理说这个bb在预处理的时候应该是window的属性。但在这里,函数声明的时候,带了一个参数bb,也就是相当于在函数体内声明了var bb。所以,函数里的bb就是函数活动对象的属性。所以函数执行时会输出2。函数执行完后,函数的活动对象被销毁,也就是局部的这个bb被删除了,执行流进入到window,再输出bb,值就是1了。输出2再输出1
6.
function Foo() { var i = 0; return function() { console.log(i++); } } var f1 = Foo(), f2 = Foo(); f1();// 0 f1();// 1 f2();// 0
一般来说函数执行完后它的局部变量就会随着函数调用结束被销毁,但是此题foo函数返回了一个匿名函数的引用(即一个闭包),它可以访问到foo()被调用产生的环境,而局部变量i一直处在这个环境中,只要一个环境有可能被访问到,它就不会被销毁,所以说闭包有延续变量作用域的功能。
其实foo()返回的是一个匿名函数,所以f1,f2相当于指向了两个不同的函数对象,所以结果f2()为0
7.找出网页中 html 的标签,并去重
[...new Set([...document.querySelectorAll('*')].map(i=>i.nodeName))]
8.考察 js 中 this 指向问题
var name = 222; var a = { name = 111, say: function () { console.log(this.name); } }; var fun = a.say; fun();// 222 直接执行函数 fun() 是 fun.call(window) 的一个简写 所以这里执行 this 指向 window a.say();// 111 a.say() 是 a.say().call(a) 的一个简写,this 指向 a var b = { name: 333, say: function (fun) { fun();// 222 这里也是直接执行函数 相当于 fun.call(window) } } b.say(a.say);// 在函数内部是直接执行 fun() b.say = a.say;// 这里把 b.say 改成了 a 对象中的 a.say() 即 b.say = function () {console.log(this.name)} b.say();// 333 相当于 b.say().call(b)
9.考察 js 函数作用域的预编译
function fn(a, c) { console.log(a); // function a() {} var a = 111; console.log(a); // 111 console.log(c); // function c() {} function a() {} // 函数声明会预编译,直接赋值给函数体 if (false) var d = 222;// 虽然没执行,也会变量提升,先声明 console.log(d); // undefined console.log(b); // undefined var b = function () {} console.log(b);// function() {} function c(){} // 函数声明会预编译,直接赋值给函数体 console.log(c);// function c() {} } fn(1, 3);
10.考察转换
var a = ??// a = 什么的时候下面会打印 1
if (a == 1 && a == 2 && a == 3) console.log(1);
// 如果是复杂类型 那么在做比较的时候 隐式的调用对象的 valueOf
var a = { i: 0, valueOf() { return ++a.i } } // 如果是复杂类型 那么在做比较的时候 隐式的调用对象的 valueOf
// 方法 2 var a = [1,2,3]; a.join = a.shift; // 利用了 [1] == 1
11.原型与原型链
var F = function() {}; Object.prototype.a = function() { console.log(1); }; Function.prototype.b = function(){ console.log(2); } var f = new F(); F.a(); F.b(); f.a(); f.b();
结果是 1、2、1、报错(Uncaught TypeError: f.b is not a function)
F 是个构造函数,而 F 是构造函数 Function 的一个实例。因为 F instanceof Object === true、F instanceof Function === true,由此我们可以得出结论:F 是 Object 和 Function 两个的实例,即 F 能访问到 a,也能访问到 b,所以 F.a() 输出 1 ,F.b() 输出 2
对于 f,f 并不是 Function 的实例,因为它本身就不是构造函数,调用的是 Function 原型链上相关属性和方法了,之能访问到 Object 原型链。所以 f.a() 输出 1 ,f.b() 就报错了
f.b() 查找路径:f 自身:没有--> f.__proto__(Object.prototype):没有--> f.__proto__.__proto__(Object.prototype.__proto__: null):招不到,报错
12.作用域(执行环境)
var result = [] var a = 3 var total = 0 function foo(a) { // a = 1 var i = 0 for (; i < 3; i++) { result[i] = function () {total += i * a; console.log(total)} } } foo(1) result.forEach(i=>{i();}) // 3 6 9
13.作用域 this
var n = 2; var obj = { n: 3, fn: (function(n) { n *= 2; this.n += 2; var n = 5; return function(m) { this.n *= 2 console.log(m + (++n)); } })(n) } var fnn = obj.fn; fnn(3); // 9 obj.fn(3); // 10 console.log(n, obj.n); // 8 6
14.原型与原型链
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();// 2 函数 Foo 的静态方法 getName();// 4 function 有提前声明的规则,声明后被 var getName = ... 覆盖,所以是 4 Foo().getName();// 1 Foo 的 return this 是 window,window.getName() 在 Foo() 里面被覆盖,则为 1 getName();// 1 同上 new Foo.getName();// 2 相当于 function a() {console.log(2)} new a() // 3 先执行了 new Foo(),返回一个对象,这个对象的 getName 为 prototype 上的 getName,相当于 (new Foo()).getName() new Foo().getName();
15.this 和 arguments
var length = 10; function fn() { console.log(this.length) } var obj = { length: 5, method: function(fn) { fn();// 10 arguments[0]()// 1 // 为什么这里是 1 ??? arguments也是对象,fn 也属于 arguments 数组中的一员,即当作为 arguments 成员之一调用的时候, // 它的作用域就绑定到了 argument 上,this 也就是指向了 arguments 对象,所以 arguments[0]() 这段代码调用了身为成员的 fn() 函数, // this.length就等于是 arguments.length ,参数为 1 个,所以最后输出 1 } } obj.method(fn)
16.闭包与异步
let i; for (i = 0; i < 3; i++) { let log = () => { console.log(i); }; setTimeout(log, 200); }// 3 3 3
for (let i = 0; i < 3; i++) { let log = () => { console.log(i); }; setTimeout(log, 200); }// 0 1 2
17.Object 和 Function 的关系
Object 和 Function 都作为JS的自带函数,Object继承自己,Function继承自己,Object 和 Function 互相继承对方,也就是说Object 和 Funtion 都既是函数也是对象。
Function instanceof Object // true Object instanceof Function // true
Object 是 Function 的实例,而 Function 是它自己的实例
18.自定义对象,prototype 原型属性
使用 Object 函数创建对象,javascript 默认创建了一个 function Object(){}
var p = new Object() p.name = 'zhangning'
使用字面量的方式创建
var p = {name: 'zhangning'}
prototype 注意细节:
1)prototype 是函数(function)的一个必备属性(书面说法是’保留属性‘)(只要是function,就一定有一个 prototype 属性)
2)prototype 的值是一个对象
3)可以任意修改函数的 prototype 属性的值
4)一个对象会自动拥有 prototype 的所有成员属性和方法
19.点运算符优先级
3.toString()
3..toString()
3...toString()
// 报错 '3' 报错
解析:
3.toString() 会被JS引擎解析成 (3.)toString() 报错 3..toString() 会被JS引擎解析成 (3.).toString() '3' 3...toString() 会被JS引擎解析成 (3.)..toString() 报错
20. 考察 . 和 = 操作符优先级
let a = {n : 1}; let b = a; a.x = a = {n: 2}; console.log(a.x) console.log(b.x)
答案:
undefined
{n: 2}
js中.操作符的优先级大于=,先执行