1 预编译 GO AO 执行期上下文问题
// GO a:undefined test:原来是a+=1 但是被替换掉了 变成 a+=3
var a = 1 // 此时 GO{a:1}
function test() {
a += 1
}
test() // GO{a:4}
function test() {
a += 3
}
test() // GO:{a:7}
console.log(a);
// 输出 7
考点:预编译(预编译环节,先变量声明提前,再给函数声明赋值,再执行
执行过程中未赋值的声明变量由于声明提前所以忽略)
2 立即执行函数的条件
function abc() {
console.log(2)
} (1,2,3) //输出结果 为空
计算机会想办法不报错,然后理解成
function abc() {
console.log(2)
}
(1,2,3)
只有 表达式 才可以变成立即执行函数
何为表达式,可以理解为数字展示,重要的是知道什么不是表达式,至少 函数声明 不是
function abc() {
console.log(2)
}() // 报错 Uncaught SyntaxError: Unexpected token
也就是说可以这样
(function abc() {
console.log(2)
}())
//2
这样
(function abc() {
console.log(2)
})() //2
甚至过分到这样
!function abc() {
console.log(2)
}() //2
+function abc() {
console.log(2)
}() //2
-function abc() {
console.log(2)
}() //2
再过分点
1,function abc() {
console.log(2)
}() //2
考点:立即执行函数的执行条件
3 闭包
首先要知道每个对象有scope属性
scope属性的下标指向作用域(执行器上下文)
比如全局的变量 var a=1
那么 window GO 对象会有个a的属性 属性值为1
var a=1,b=2,f="f1"
function fun1 (){
var c=3
var d=4
var f="f2"
}
// 定义一个函数 fun1 那么fun1的 scope[0]指向自己的AO scope[1]指向window GO
fun1.scope[
AO:{c:3,
d:4,
f:"f2"
},
GO{
fun1:function(){...},
a:1,
b:2,
f:"f1"
}
]
// 此时fun1可以优先使用自己的AO,再考虑GO 并且GO访问不了AO里的属性
console.log(a) //1
console.log(f1) //"f1"
console.log(c) // 报错 : c is not defined
如果在fun1的基础上再声明一个函数fun2,也同理 fun2可以使用 fun,以及GO的参数 但是 fun1和全局无法访问fun2的参数
也就是说fun2可以在fun1的基础上使用fun1的变量,那么把fun2返回出来 就形成闭包 此时可以利用闭包做一个记忆的功能
写一组li 每点击里面的一个能打印出自己的下标
<ul>
<li>123li>
<li>123li>
<li>123li>
<li>123li>
<li>123li>
<li>123li>
ul>
<script>
var li = document.getElementsByTagName('li')
for (var i = 0; i < li.length; i++) {
(function (j) {
li[i].onclick = function () {
console.log(j)
}
}(i))
}// 又或者可以用let,让for的值形成块级作用域,也可以不用闭包
for(let i=0; i<li.length; i++){
li[i].onclick=function(){
console.log(i)
}
script>
parseInt(3,8)
parseInt(3,2)
parseInt(3,0)
A 3, 3 , 3
B 3, 3, NaN
C 3,NaN,NaN √ parseInt是以第二位数为第一位数的进制, 二进制不可能有3 所以NaN
D other
A string √
B array
C object √
D null
array, object, null 经过typeof都返回 字符串object
函数 返回 function 字符串返回 String 数字 Number
undefined 返回 undefined boolean返回boolean
返回的全都是字符串
A undefined == null√
B undefined===null
C isNaN(“100”)
D parseInt(“1a”)==1 √
// alibaba 面试题:
var obj = {
'2': 'a',
'3': 'b',
"length": 2,
"push": Array.prototype.push
}
obj.push("c")
obj.push("d")
console.log(obj); // {'2':"c",'3':"d",'length':4}
/*
// push 原理
Array.prototype.push = function (target) {
this[this.length] = target;
this.length++
}
*/
使用sort排序 在回掉函数里使用随机数return整数或者负数
arr.sort(function (a, b) {
return Math.round(Math.random()*10)/10 -0.5
})
** 隐式转换**
引用值的隐式类型转换
隐式调用包装类 或string 或number
[]+ "" // ""
[]+ 1 // '1'
[] + 2 // "2"
Number([]) // 0
[] -1 // -1
[] /2 //0
{}+1 /1
Number({}) // 1
[] ==[] // false
[] == {} // false
** 私有化变量**
new出来的只能用自己变量 不会影响构造函数
function Person(name, age, sex) {
this.age = age
this.name = name;
this.sex = sex
var a = 0
function sss() {
a++;
console.log(a)
};
this.say = sss
}
var oPerson = new Person()
oPerson.say() //1
oPerson.say() // 2
var oPerson2 = new Person()
oPerson2.say() //1
** delete 删除变量 **
arguments的形参相当于 var 的变量 无法删除 接着程序该怎么执行怎么执行
(function (x) {
delete x;
console.log(x)
}(1))
** 函数表达式和定义 **
当 一个变量 = 函数时 此时是函数声明 function的名字没有意义
var h = function a() {
return 1
}
typeof a()
// ReferenceError: a is not defined
** div在页面中居中显示 **
绝对定位 left,top 50% margin = -1/2 高,宽
绝对定位 上下左右都是0 marign auto
div{
width:200px;
height:200px;
position: absolute;
top:50%;
left:50%;
background:slategray;
margin:-100px 0 0 -100px ;
}
div{
width:200px;
height:200px;
position: absolute;
top:0;
left:0;
right: 0;
bottom: 0;
background:slategray;
margin:auto;
}
** this的终极问题 **
谁调用,this就指向谁, 第三个传递的只是函数方法,没有传递this指向
在某个环境里执行不算被调用 ,this不会改指向
var name = '222';
var a = {
name: "111",
say: function () {
console.log(this.name);
}
}
var fun = a.say
fun() // 222
a.say() // 111
var b = {
name: "333",
say: function (fun) {
// 如果 (this.fun())调用 那么 { this = b }
// 如果没有this 那么谁也没调用,this指向window { this = window }
// 此时 fun = function () {console.log(this.name)}
fun() // 222
test() // window 区域执行不算不打点不算被某个函数调用
}
}
b.say(a.say) // 222
b.say = a.say
b.say() // 333
function test(){
console.log(this)
}
** 阅读代码,写结果 **
即使不用new this也生效会改变window的同名变量
var foo = 123;
function print() {
var foo = 234;
this.foo = 567
console.log(foo); // 没有用this改变指向,所以指向AO的foo
}
print() //234
console.log(foo); // 567 被内部的this改变
用new 执行print
var foo = 123;
function print() {
// 用 new 那么 this = Object.create(price.prototype)
//相当于创建了一个空对象=>结果就是一个{undefined}__proto__ 是 price.prototype
// 此时this 不会改变window的foo
this.foo = 234; // 给{undefined}赋值为 {foo:234}
var foo =567
console.log(foo); // 567 这个foo只是私有化的变量
}
new print() // 用new调用,this不再指向全局,不能改变window.foo
console.log(foo); // 123
// 657
// 123
** 直接执行test 和 new test的执行结果 **
因为new this没有申明a 所以是undefined
var a = 5
function test() {
a = 0;
cosnole.log(a);
cosnole.log(this.a);
var a;
cosnole.log(a)
}
test() // 050
new test() // 0 undefined 0
** apply call bind **
bind相当于call,改变了this的指向但是不会自动调用函数
function print() {
var marty = {
name: "marty",
printName: function () {
console.log(this.name);
}
}
var test1 = { name: "test1" }
var test2 = { name: "test2" }
var test3 = { name: "test3" }
test3.printName = marty.printName
// bind改变了函数的运行环境 不会主动调用printName方法
// 相当于 {name:123,prinName:function(){cosnole.log(this.name}}
var printName2 = marty.printName.bind({ name: 123 })
marty.printName.call(test1) // test1
// apply传入参数形式为数组,此时并没有传参只是改变指向
marty.printName.apply(test2) // test2
marty.printName(); // marty
printName2(); // 123
test3.printName() // test3
}
print()
** 作用域改变 **
函数连续调用 内部可以改变外部的变量
var bar = { a: "002" }
function print() {
bar.a = "a";
Object.prototype.b = 'b';
return function inner() {
console.log(bar.a); // a
console.log(bar.b); // b
}
}
print()()
** 函数的作用域,以及调用 **
var x = 10
var obj = {
x: 30,
f: function () {
console.log(this.x);
}
}
function show(f) {
var that = obj;
var x = 20;
f() // 10 不受x=20影响 因为作用域根据函数定义的地方决定
// 此时 this指向的是window
obj.f() // 30 被 obj调用 this 指向 obj
that.f() // 30
}
show(obj.f);