6

变量类型和计算知识点:

值类型、引用类型

//值类型
var a=100
var b=a
a=200
console.log(b) //100
//引用类型
var a={age:20}
var b=a
b.age=21
console.log(a.age) //21

typeof

// Numbers
typeof 37 === 'number';
typeof 3.14 === 'number';
typeof Math.LN2 === 'number';
typeof Infinity === 'number';
typeof NaN === 'number'; // 尽管NaN是"Not-A-Number"的缩写
typeof Number(1) === 'number'; // 但不要使用这种形式!
// Strings
typeof "" === 'string';
typeof "bla" === 'string';
typeof (typeof 1) === 'string'; // typeof总是返回一个字符串
typeof String("abc") === 'string'; // 但不要使用这种形式!
// Booleans
typeof true === 'boolean';
typeof false === 'boolean';
typeof Boolean(true) === 'boolean'; // 但不要使用这种形式!
// Symbols
typeof Symbol() === 'symbol';
typeof Symbol('foo') === 'symbol';
typeof Symbol.iterator === 'symbol';
// Undefined
typeof undefined === 'undefined';
typeof declaredButUndefinedVariable === 'undefined';
typeof undeclaredVariable === 'undefined'; 
// Objects
typeof {a:1} === 'object';
// 使用Array.isArray 或者 Object.prototype.toString.call
// 区分数组,普通对象
typeof [1, 2, 4] === 'object';
typeof new Date() === 'object';
// 下面的容易令人迷惑,不要使用!
typeof new Boolean(true) === 'object';
typeof new Number(1) ==== 'object';
typeof new String("abc") === 'object';
// 函数
typeof function(){} === 'function';
typeof Math.sin === 'function';
//NaN
typeof 1/0 === 'NaN';
//null
typeof null === 'object';

强制类型转换

//逻辑运算符
console.log(10 & 0) //0  转换为true&&0
console.log(''||'abc') //abc  转换为false||'abc'
console.log(!window.abc) //true  !undefined为true
//if语句 false情况
null '' false 0 NaN undefined
//判断一个变量是否当作true或者false
var a = 100
console.log(!!a)

面试题:

1.JS中使用typeof能得到哪些类型
undefined null string number object function boolean symbol
2.何时使用'===',何时使用'=='
参考jQuery源码 只有这种情况下使用'==':

if(obj.a == null) {
}
//这句相当于obj.a === null || obj.a === undefined

3.JS有哪些内置函数
Object Array String Number Function Boolean Date RegExp Error
4.JS变量按照存储方式分为哪些类型,并描述其特点
值类型、引用类型。
值类型是将变量的值存在内存中。
引用类型的变量是真实变量的指针(对象、数组、函数)。可以无限扩张属性。
5.如何理解JSON
是JavaScript的对象,内置两个方法 JSON.stringify JSON.parse

原型知识点:

构造函数

function Foo(name, age) {
  this.name = name
  this.age = age 
  this.class = 'class-1'
  //return this  默认有这行
}

var f = new Foo('zs', 20)

//执行过程:1.new函数执行时this会变成空对象 2.this. 的时候赋值 3.return this 4.给f赋值


//var a = {}         ===> var a = new Object()
//var a =[]          ===> var a = new Array()
//function Foo(){}   ===> var Foo = new Function()
//instanceof 用于判断一个函数是否是一个变量的构造函数

原型规则

//所有的引用类型(数组、对象、函数)都具有对象特性,除了null之外,都可以自由扩展属性
//所有的引用类型 都有__proto__ 隐式原型
//所有的函数都有 prototype 显式原型   属性值也是一个普通对象
//所有的引用类型(数组、对象、函数),__proto__属性值指向它的构造函数的prototype属性值
var obj = {}; obj.a = 100
var arr = []; arr.a = 100
function fn () {}
fn.a = 100

console.log(obj.__proto__)
console.log(arr.__proto__)
console.log(fn.__proto__)

console.log(fn.prototype)

console.log(obj.__proto__ === Object.prototype)


//试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的__proto__(构造函数的prototype)中寻找
function Foo(name, age) {
  this.name = name
}

Foo.prototype.alertName = function () {
  alert(this.name)
}

var f = new Foo('zs')
f.printName = function () {
  console.log(this.name)
}

f.printName()
f.alertName()

原型链 instanceof

//instanceof 是用于判断引用类型属于哪个构造函数的方法
//构造函数
function Foo(name, age) {
  this.name = name
}

Foo.prototype.alertName = function () {
  alert(this.name)
}

//创建实例
var f = new Foo('zs')
f.printName = function () {
  console.log(this.name)
}


f.printName()
f.alertName()
f.toString()


// f instanceof Foo 判断过程:
// f 的 __proto__一层层往上找到是否对应Foo.prototype
// 再判断f instanceof Object

直角矩形是构造函数 圆角矩形是对象
clipboard.png

hasOwnProperty

var obj={
x:100,
y:200,
z:300
}
var key
for(key in obj){
//hasOwnProperty会返回一个布尔值,判断是否是原生的属性,以此来排除原型链上的属性
if(obj.hasOwnProperty(key)){
  console.log(key,obj[key]);
}
}
//x 100
//y 200
//z 300

面试题

6.如何准确判断一个变量是数组函数

var arr = []
arr instanceof Array
typeof arr //object, typeof 是无法判断是否是数组的

7.写一个原型链继承的例子

function Elem(id) {
  this.elem = document.getElementById(id)
}

Elem.prototype.html = function (val) {
  var elem = this.elem
  if (val) {
    elem.innerHTML = val
    return this
  } else {
    return elem.innerHTML
  }
}

Elem.prototype.on = function (type, fn) {
  var elem = this.elem
  elem.addEventListener(type, fn)
  return this
}

var div1 = new Elem('wrapper')
div1.html('<p>hello</p>').on('click', function () {
  alert('clicked')
}).html('<p>javascript</p>')

8.描述new一个对象的过程

//创建一个对象
//this指向这个对象
//执行代码  即对this赋值
//返回this
function Foo(name, age) {
  this.name = name 
  this.age = age
  this.class = 'class-1'
  //return this   构造函数最好不要写return
}

var f = new Foo('zs', 20)

作用域和闭包知识点:

执行上下文

//执行上下文:当前被执行代码的环境/作用域
console.log(a)
var a = 100

fn('zs')
//函数声明
function fn(name) {

  console.log(this)
  console.log(arguments)

  age = 20
  console.log(name, age)
  var age

  bar(100)

  function bar(num) {
    console.log(num)
  }
}
//函数表达式: var fn = function () {}


//在全局代码执行前,会将变量定义和函数声明先提出来
//在函数代码执行前,会将变量定义,函数声明,this,arguments(所有参数的集合)先提出来

this

//this的值执行时才能确定
var a = {
  name: 'A',
  fn: function () {
    console.log(this.name)  //这个阶段的this无法确定值
  }
}


a.fn()                  //this === a
a.fn.call({name: 'B'})  //this === {name: 'B'}
var fn1 = a.fn
fn1()                   //this === window

//作为构造函数执行
function Foo(name) {
  // this = {}
  this.name = name
  // return this
}
var f = new Foo('zs')
//作为对象属性执行
var obj = {
  name: 'A',
  printName: function () {
    console.log(this.name)    //这里this就是obj
  }
}
obj.printName
//作为普通函数执行
function fn() {
  console.log(this)       //这里的this就是window
}
fn
//call apply bind
function fn1(name, age) {
  console.log(name)
  console.log(this)       //这里的this是{x:100}
}
fn1.call({x:100}, 'zs', 20)


var fn2h = function fn2(name, age) {
  console.log(name)
  console.log(this)       //这里的this是{y:200}
}.bind({y:200})
fn2('zs', 20)

作用域 作用域链

//不断向父级作用域寻找变量的过程形成了作用域链
//没有块级作用域概念
if (true) {
  var name = 'zs'
}
console.log(name)


//函数、全局作用域
var a = 10
function fn() {
  var a = 200
  console.log('fn', a)
}
console.log('global', a)
fn()


var b = 100
function fn() {
  var c = 200

  console.log(b)  //当前作用域没有定义的变量叫做自由变量
  console.log(c)  
}
fn()

var a = 100
function f1() {
  var b = 200
  function f2() {
    var c = 300

    console.log(a)
    console.log(b)
    console.log(c)
  }
  f2()
}
f1()
//哪个作用域定义了f1这个函数,f1的父级作用域就是谁

闭包

//闭包应用:1.函数作为返回值
function F1() {
  var a = 100

  //返回一个函数  
  return function () {
    console.log(a)     //100
  }
}

//f1得到一个函数
var f1 = F1()
var a = 200
f1()


//2.函数作为参数传递
function F1() {
  var a = 100
  return function() {
    console.log(a)  //100
  }
}

var f1 = F1()

function F2(fn) {
  var a = 200
  fn()
}
F2(f1)

面试题

9.说一下对变量提升的理解
变量定义、函数声明会提前。
10.说明this几种不同的使用场景
作为构造函数、对象属性、普通函数执行,call apply bind
11.创建10个<a>标签,点击时弹出对应序号

var i
  for (i = 0; i < 10; i++) {
    (function (i) {
      var a = document.createElement('a')
      a.innerHTML = i + '<br>'
      a.addEventListener('click', function (e) {
        e.preventDefault()
        alert(i)
      })
      document.body.appendChild(a)
    })(i)
  }

12.如何理解作用域
自由变量、作用域链,即自由变量的寻找、闭包的两个场景。
13.实际开发中闭包的应用
封装变量,收敛权限 案例:

function isFirstLoad() {
  var _list = []
  return function (id) {
    if (_list.indexOf(id) >=0) {
      return false
    } else {
      _list.push(id)
      return true
    }
  }
}

var firstLoad = isFirstLoad()
console.log(firstLoad(10))
console.log(firstLoad(10))
console.log(firstLoad(20))
console.log(firstLoad(20))

imgwho
78 声望7 粉丝

undefined